This is scheme48.info, produced by makeinfo version 6.7 from
scheme48.texi.

This manual is for Scheme48 version 1.3.

   Copyright (C) 2004, 2005, 2006 Taylor Campbell.  All rights reserved.

   This manual includes material derived from works bearing the
following notice:

   Copyright (C) 1993-2005 Richard Kelsey, Jonathan Rees, and Mike
Sperber.  All rights reserved.

     Redistribution and use in source and binary forms, with or without
     modification, are permitted provided that the following conditions
     are met:

        * Redistributions of source code must retain the above copyright
          notice, this list of conditions and the following disclaimer.

        * Redistributions in binary form must reproduce the above
          copyright notice, this list of conditions and the following
          disclaimer in the documentation and/or other materials
          provided with the distribution.

        * The name of the authors may not be used to endorse or promote
          products derived from this software without specific prior
          written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

INFO-DIR-SECTION The Algorithmic Language Scheme
START-INFO-DIR-ENTRY
* Scheme48: (scheme48).	Nearly complete reference manual for version 1.3
END-INFO-DIR-ENTRY


File: scheme48.info,  Node: Top,  Next: Introduction & acknowledgements,  Up: (dir)

The Nearly Complete Scheme48 Reference Manual
*********************************************

This manual is for Scheme48 version 1.3.

   Copyright (C) 2004, 2005, 2006 Taylor Campbell.  All rights reserved.

   This manual includes material derived from works bearing the
following notice:

   Copyright (C) 1993-2005 Richard Kelsey, Jonathan Rees, and Mike
Sperber.  All rights reserved.

     Redistribution and use in source and binary forms, with or without
     modification, are permitted provided that the following conditions
     are met:

        * Redistributions of source code must retain the above copyright
          notice, this list of conditions and the following disclaimer.

        * Redistributions in binary form must reproduce the above
          copyright notice, this list of conditions and the following
          disclaimer in the documentation and/or other materials
          provided with the distribution.

        * The name of the authors may not be used to endorse or promote
          products derived from this software without specific prior
          written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

* Menu:

* Introduction & acknowledgements::
* User environment::
* Module system::
* System facilities::
* Multithreading::
* Libraries::
* C interface::
* POSIX interface::
* Pre-Scheme::			A low-level dialect of Scheme
* References::
* Concept index::
* Binding index::
* Structure index::

-- The Detailed Node Listing --

* Introduction & acknowledgements::

User environment

* Running Scheme48::
* Emacs integration::
* Using the module system::
* Command processor::

Module system

* Module system architecture::
* Module configuration language::	Language of the module system
* Macros in concert with modules::
* Static type system::

System facilities

* System features::
* Condition system::
* Bitwise manipulation::
* Generic dispatch system::
* I/O system::
* Reader & writer::
* Records::
* Suspending and resuming heap images::

Multithreading

* Basic thread operations::
* Optimistic concurrency::
* Higher-level synchronization::
* Concurrent ML::			High-level event synchronization
* Pessimistic concurrency::		Mutual exclusion/locking
* Custom thread synchronization::

Libraries

* Boxed bitwise-integer masks::
* Enumerated/finite types and sets::
* Macros for writing loops::
* Library data structures::
* I/O extensions::
* TCP & UDP sockets::
* Common-Lisp-style formatting::
* Library utilities::

C interface

* Shared bindings between Scheme and C::
* Calling C functions from Scheme::
* Dynamic loading of C modules::
* Accessing Scheme data from C::
* Calling Scheme procedures from C::
* Interacting with the Scheme heap in C::
* Using Scheme records in C::
* Raising exceptions from C::
* Unsafe C macros::

POSIX interface

* POSIX processes::
* POSIX signals::
* POSIX process environment::
* POSIX users and groups::
* POSIX host OS and machine identification::
* POSIX file system access::
* POSIX time::
* POSIX I/O utilities::
* POSIX regular expressions::
* POSIX C to Scheme correspondence::


Pre-Scheme

* Differences between Pre-Scheme & Scheme::
* Pre-Scheme type specifiers::
* Standard Pre-Scheme environment::
* More Pre-Scheme packages::
* Invoking the Pre-Scheme compiler::
* Example Pre-Scheme compiler usage::
* Running Pre-Scheme as Scheme::



File: scheme48.info,  Node: Introduction & acknowledgements,  Next: User environment,  Prev: Top,  Up: Top

1 Introduction
**************

Scheme48 is an implementation of Scheme based on a byte-code virtual
machine with design goals of simplicity and cleanliness.  To briefly
enumerate some interesting aspects of it, Scheme48 features:
   * an advanced module system based on Jonathan Rees's W7 security
     kernel with well-integrated interaction between macros and modules;

   * a virtual machine written in a dialect of Scheme itself,
     Pre-Scheme, for which a compiler is written with Scheme48;

   * a sophisticated, user-level, preëmptive multithreading system with
     numerous high-level concurrency abstractions;

   * a composable, lock-free shared-memory thread synchronization
     mechanism known as "optimistic concurrency"; and

   * an advanced user environment that is well-integrated with the
     module and thread systems to facilitate very rapid development of
     software systems scaling from small to large and single-threaded to
     multi-threaded.

   It was originally written by Jonathan Rees and Richard Kelsey in 1986
in response to the fact that so many Lisp implementations had started
out simple and grown to be complex monsters of projects.  It has been
used in a number of research areas, including:
   * mobile robots at Cornell [Donald 92];

   * a multi-user collaboration system, sometimes known as a 'MUD'
     ('multi-user dungeon') or 'MUSE' ('multi-user simulation
     environment'), as well as general research in capability-based
     security [Museme; Rees 96]; and

   * advanced distributed computing with higher-order mobile agents at
     NEC's Princeton research lab [Cejtin et al.  95].

   The system is tied together in a modular fashion by a configuration
language that permits quite easy mixing and matching of components, so
much so that Scheme48 can be used essentially as its own OS, as it was
in Cornell's mobile robots program, or just as easily within another, as
the standard distribution is.  The standard distribution is quite
portable and needs only a 32-bit byte-addressed POSIX system.

   The name 'Scheme48' commemorates the time it took Jonathan Rees and
Richard Kelsey to originally write Scheme48 on August 6th & 7th, 1986:
forty-eight hours.  (It has been joked that the system has expanded to
such a size now that it requires forty-eight hours to _read_ the
source.)

1.1 This manual
===============

This manual begins in the form of an introduction to the usage of
Scheme48, suitable for those new to the system, after which it is
primarily a reference material, organized by subject.  Included in the
manual is also a complete reference manual for Pre-Scheme, a low-level
dialect of Scheme for systems programming and in which the Scheme48
virtual machine is written; *note Pre-Scheme::.

   This manual is, except for some sections pilfered and noted as such
from the official but incomplete Scheme48 reference manual, solely the
work of Taylor Campbell, on whom all responsibility for the content of
the manual lies.  The authors of Scheme48 do not endorse this manual.

1.2 Acknowledgements
====================

Thanks to Jonathan Rees and Richard Kelsey for having decided so many
years ago to make a simple Scheme implementation with a clean design in
the first place, and for having worked on it so hard for so many years
(almost twenty!); to Martin Gasbichler and Mike Sperber, for having
picked up Scheme48 in the past couple years when Richard and Jonathan
were unable to work actively on it; to Jeremy Fincher for having asked
numerous questions about Scheme48 as he gathered knowledge from which he
intended to build an implementation of his own Lisp dialect, thereby
inducing me to decide to write the manual in the first place; to Jorgen
Schäfer, for having also asked so many questions, proofread various
drafts, and made innumerable suggestions to the manual.


File: scheme48.info,  Node: User environment,  Next: Module system,  Prev: Introduction & acknowledgements,  Up: Top

2 User environment
******************

* Menu:

* Running Scheme48::
* Emacs integration::
* Using the module system::
* Command processor::


File: scheme48.info,  Node: Running Scheme48,  Next: Emacs integration,  Up: User environment

2.1 Running Scheme48
====================

Scheme48 is run by invoking its virtual machine on a dumped heap image
to resume a saved system state.  The common case of invoking the default
image, 'scheme48.image', which contains the usual command processor,
run-time system, &c., is what the 'scheme48' script that is installed
does.  The actual virtual machine executable itself, 'scheme48vm', is
typically not installed into an executable directory such as
'/usr/local/bin/' on Unix, but in the Scheme48 library directory, which
is, by default on Unix installations of Scheme48, '/usr/local/lib/'.
However, both 'scheme48' and 'scheme48vm' share the following
command-line options; the only difference is that 'scheme48' has a
default '-i' argument.

'-h HEAP-SIZE'
     The size of Scheme48's heap, in cells.  By default, the heap size
     is 3 megacells, or 12 megabytes, permitting 6 megabytes per
     semispace -- Scheme48 uses a simple stop & copy garbage
     collector.(1)  Since the current garbage collector cannot resize
     the heap dynamically if it becomes consistently too full, users on
     machines with much RAM may be more comfortable with liberally
     increasing this option.

'-s STACK-SIZE'
     The stack size, in cells.  The default stack size is 10000 bytes,
     or 2500 cells.  Note that this is only the size of the stack cache
     segment of memory for fast stack frame storage.  When this
     overflows, there is no error; instead, Scheme48 simply copies the
     contents of the stack cache into the heap, until the frames it
     copied into the heap are needed later, at which point they are
     copied back into the stack cache.  The '-s' option therefore
     affects only performance, not the probability of fatal stack
     overflow errors.

'-i IMAGE-FILENAME'
     The filename of the suspended heap image to resume.  When running
     the 'scheme48' executable, the default is the regular Scheme48
     image; when running the virtual machine directly, this option must
     be passed explicitly.  For information on creating custom heap
     images, *note Image-building commands::, and also *note Suspending
     and resuming heap images::.

'-a ARGUMENT ...'
     Command-line arguments to pass to the heap image's resumer, rather
     than being parsed by the virtual machine.  In the usual Scheme48
     command processor image, these arguments are put in a list of
     strings that will be the initial focus value (*note Focus value::).

'-u'
     Muffles warnings on startup about undefined imported foreign
     bindings.

   The usual Scheme48 image may accept an argument of 'batch', using the
'-a' switch to the virtual machine.  This enters Scheme48 in batch mode,
which displays no welcoming banner, prints no prompt for inputs, and
exits when an EOF is read.  This may be used to run scripts from the
command-line, often in the exec language (*note Command programs::), by
sending text to Scheme48 through Unix pipes or shell heredocs.  For
example, this Unix shell command will load the command program in the
file 'foo.scm' into the exec language environment and exit Scheme48 when
the program returns:

     echo ,exec ,load foo.scm | scheme48 -a batch

This Unix shell command will load 'packages.scm' into the module
language environment, open the 'tests' structure into the user
environment, and call the procedure 'run-tests' with zero arguments:

     scheme48 -a batch <<END
     ,config ,load packages.scm
     ,open tests
     (run-tests)
     END

   Scheme48 also supports [SRFI 22] and [SRFI 7] by providing R5RS and
[SRFI 7] script interpreters in the location where Scheme48 binaries are
kept as 'scheme-r5rs' and 'scheme-srfi-7'.  See the [SRFI 22] and [SRFI
7] documents for more details.  Scheme48's command processor also has
commands for loading [SRFI 7] programs, with or without a [SRFI 22]
script header; *note SRFI 7::.

2.1.1 Command processor introduction
------------------------------------

The Scheme48 command processor is started up on resumption of the usual
Scheme48 image.  This is by default what the 'scheme48' script installed
by Scheme48 does.  It will first print out a banner that contains some
general information about the system, which will typically look
something like this:

     Welcome to Scheme 48 1.3 (made by root on Sun Jul 10 10:57:03 EDT 2005)
     Copyright (c) 1993-2005 by Richard Kelsey and Jonathan Rees.
     Please report bugs to scheme-48-bugs@s48.org.
     Get more information at http://www.s48.org/.
     Type ,? (comma question-mark) for help.

After the banner, it will initiate a REPL (read-eval-print loop).  At
first, there should be a simple '>' prompt.  The command processor
interprets Scheme code as well as "commands".  Commands operate the
system at a level above or outside Scheme.  They begin with a comma, and
they continue until the end of the line, unless they expect a Scheme
expression argument, which may continue as many lines as desired.  Here
is an example of a command invocation:

     > ,set load-noisily on

This will set the 'load-noisily' switch (*note Command processor
switches::) on.

   *Note:* If a command accepts a Scheme expression argument that is
followed by more arguments, all of the arguments after the Scheme
expression must be put on the same line as the last line of the Scheme
expression.

   Certain operations, such as breakpoints and errors, result in a
recursive command processor to be invoked.  This is known as "pushing a
command level".  *Note Command levels::.  Also, the command processor
supports an "object inspector", an interactive program for inspecting
the components of objects, including continuation or stack frame
objects; the debugger is little more than the inspector, working on
continuations.  *Note Inspector::.

   Evaluation of code takes place in the "interaction environment".
(This is what R5RS's 'interaction-environment' returns.)  Initially,
this is the "user environment", which by default is a normal R5RS Scheme
environment.  There are commands that set the interaction environment
and evaluate code in other environments, too; *note Module commands::.

   The command processor's prompt has a variety of forms.  As above, it
starts out with as a simple '>'.  Several factors can affect the prompt.
The complete form of the prompt is as follows:

   * It begins with an optional command level (*note Command levels::)
     number: at the top level, there is no command level number; as
     command levels are pushed, the number is incremented, starting at
     1.

   * Optionally, the name of the interaction environment follows the
     command level number: if the interaction environment is the user
     environment, there is no name printed here; named environments are
     printed with their names; unnamed environments (usually created
     using the ',new-package' command; *note Module commands::) are
     printed with their numeric identifiers.  If a command level number
     preceded an environment name, a space is printed between them.

   * If the command processor is in the regular REPL mode, it ends with
     a '>' and a space before the user input area; if it is in inspector
     mode (*note Inspector::), it ends with a ':' and a space before the
     user input area.

   For example, this prompt denotes that the user is in inspector mode
at command level 3 and that the interaction environment is an
environment named 'frobozz':

     3 frobozz:

   This prompt shows that the user is in the regular REPL mode at the
top level, but in the environment for module descriptions (*note Module
commands::):

     config>

   For a complete listing of all the commands in the command processor,
*note Command processor::.

   ---------- Footnotes ----------

   (1) The Scheme48 team is also working on a new, generational garbage
collector, but it is not in the standard distribution of Scheme48 yet.


File: scheme48.info,  Node: Emacs integration,  Next: Using the module system,  Prev: Running Scheme48,  Up: User environment

2.2 Emacs integration
=====================

Emacs is the canonical development environment for Scheme48.  The
'scheme.el' and 'cmuscheme.el' packages provide support for editing
Scheme code and running inferior Scheme processes, respectively.  Also,
the 'scheme48.el' package provides more support for integrating directly
with Scheme48.(1)  'scheme.el' and 'cmuscheme.el' come with GNU Emacs;
'scheme48.el' is available separately from

     <http://www.emacswiki.org/cgi-bin/wiki/download/scheme48.el>.

   To load 'scheme48.el' if it is in the directory EMACS-DIR, add these
lines to your '.emacs':

     (add-to-list 'load-path "EMACS-DIR/")
     (autoload 'scheme48-mode "scheme48"
       "Major mode for improved Scheme48 integration."
       t)
     (add-hook 'hack-local-variables-hook
               (lambda ()
                 (if (and (boundp 'scheme48-package)
                          scheme48-package)
                     (progn (scheme48-mode)
                            (hack-local-variables-prop-line)))))

   The 'add-hook' call sets Emacs up so that any file with a
'scheme48-package' local variable specified in the file's '-*-' line or
'Local Variables' section will be entered in Scheme48 mode.  Files
should use the 'scheme48-package' variable to enable Scheme48 mode; they
should not specify Scheme48 mode explicitly, since this would fail in
Emacs instances without 'scheme48.el'.  That is, put this at the tops of
files:

     ;;; -*- Mode: Scheme; scheme48-package: ... -*-

Avoid this at the tops of files:

     ;;; -*- Mode: Scheme48 -*-

   There is also SLIME48, the Superior Lisp Interaction Mode for Emacs
with Scheme48.  It provides a considerably higher level of integration
the other Emacs packages do, although it is less mature.  It is at

     <http://mumble.net/~campbell/scheme/slime48.tar.gz>;

there is also a Darcs repository(2) at

     <http://mumble.net/~campbell/darcs/slime48/>.

   Finally, 'paredit.el' implements pseudo-structural editing facilities
for S-expressions: it automatically balances parentheses and provides a
number of high-level operations on S-expressions.  'Paredit.el' is
available on the web at

     <http://mumble.net/~campbell/emacs/paredit.el>.

   'cmuscheme.el' defines these:

 -- Emacs command: run-scheme [scheme-prog]
     Starts an inferior Scheme process or switches to a running one.
     With no argument, this uses the value of 'scheme-program-name' to
     run the inferior Scheme system; with a prefix argument SCHEME-PROG,
     this invokes SCHEME-PROG.

 -- Emacs variable: scheme-program-name
     The Scheme program to invoke for inferior Scheme processes.

   Under 'scheme48-mode' with 'scheme.el', 'cmuscheme.el', and
'scheme48.el', these keys are defined:

'C-M-f' -- 'forward-sexp'
'C-M-b' -- 'backward-sexp'
'C-M-k' -- 'kill-sexp'
'<ESC> C-<DEL>' (_not_ 'C-M-<DEL>') -- 'backward-kill-sexp'
'C-M-q' -- 'indent-sexp'
'C-M-@' -- 'mark-sexp'
'C-M-<SPC>' -- 'mark-sexp'
     S-expression manipulation commands.  'C-M-f' moves forward by one
     S-expression; 'C-M-b' moves backward by one.  'C-M-k' kills the
     S-expression following the point; '<ESC> C-<DEL>' kills the
     S-expression preceding the point.  'C-M-q' indents the S-expression
     following the point.  'C-M-@' & 'C-M-<SPC>', equivalent to one
     another, mark the S-expression following the point.

'C-c z' -- 'switch-to-scheme'
     Switches to the inferior Scheme process buffer.

'C-c C-l' -- 'scheme48-load-file'
     Loads the file corresponding with the current buffer into Scheme48.
     If that file was not previously loaded into Scheme48 with 'C-c
     C-l', Scheme48 records the current interaction environment in place
     as it loads the file; if the file was previously recorded, it is
     loaded into the recorded environment.  *Note Emacs integration
     commands::.

'C-c C-r' -- 'scheme48-send-region'
'C-c M-r' -- 'scheme48-send-region-and-go'
     'C-c C-r' sends the currently selected region to the current
     inferior Scheme process.  The file of the current buffer is
     recorded as in the 'C-c C-l' command, and code is evaluated in the
     recorded package.  'C-c M-r' does similarly, but subsequently also
     switches to the inferior Scheme process buffer.

'C-M-x' -- 'scheme48-send-definition'
'C-c C-e' -- 'scheme48-send-definition'
'C-c M-e' -- 'scheme48-send-definition-and-go'
     'C-M-x' (GNU convention) and 'C-c C-e' send the top-level
     definition that the current point is within to the current inferior
     Scheme process.  'C-c M-e' does similarly, but subsequently also
     switches to the inferior Scheme process buffer.  'C-c C-e' and 'C-c
     M-e' also respect Scheme48's file/environment mapping.

'C-x C-e' -- 'scheme48-send-last-sexp'
     Sends the S-expression preceding the point to the inferior Scheme
     process.  This also respects Scheme48's file/environment mapping.

   ---------- Footnotes ----------

   (1) 'scheme48.el' is based on the older 'cmuscheme48.el', which is
bundled with Scheme48 in the 'emacs/' directory.  Since 'cmuscheme48.el'
is older and less developed, it is not documented here.

   (2) Darcs is a revision control system; see

     <http://www.darcs.net/>

for more details.


File: scheme48.info,  Node: Using the module system,  Next: Command processor,  Prev: Emacs integration,  Up: User environment

2.3 Using the module system
===========================

Scheme48 is deeply integrated with an advanced module system.  For
complete detail of its module system, *note Module system::.  Briefly,
however:

   * "Packages" are top-level environments suitable for evaluating
     expressions and definitions, either interactively, from files
     loaded on-the-fly, or as the bodies of modules.  They can also
     access bindings exported by structures by "opening" the structures.

   * "Structures" are libraries, or implementations of interfaces,
     exporting sets of bindings that packages can access.  Underlying
     structures are usually packages, in which the user can, in some
     cases, interactively evaluate code during development.

   Scheme48's usual development system, the command processor, provides
a number of commands for working with the module system.  For complete
details, *note Module commands::.  Chief among these commands are
',open' and ',in'.  ',open STRUCT ...' makes all of the bindings from
each of STRUCT ... available in the interaction environment.  Many of
the sections in this manual describe one or more structures with the
name they are given.  For example, in order to use, or open, the
multi-dimensional array library in the current interaction environment,
one would enter

     ,open arrays

to the command processor.  ',in STRUCT' sets the interaction environment
to be the package underlying STRUCT.  For instance, if, during
development, the user decides that the package of the existing structure
'foo' should open the structure 'bar', he might type

     ,in foo
     ,open bar

   The initial interaction environment is known as the "user package";
the interaction environment may be reverted to the user package with the
',user' command.

   Module descriptions, or code in the module configuration language
(*note Module configuration language::) should be loaded into the
special environment for that language with the ',config' command (*note
Module commands::).  E.g., if 'packages.scm' contains a set of module
descriptions that the user wishes to load, among which is the definition
of a structure 'frobozz' which he wishes to open, he will typically send
the following to the command processor prompt:

     ,config ,load packages.scm
     ,open frobozz

   *Note:* These are commands for the interactive command processor,
_not_ special directives to store in files to work with the module
system.  The module language is disjoint from Scheme; for complete
detail on it, *note Module system::.

2.3.1 Configuration mutation
----------------------------

(This section was derived from work copyrighted (C) 1993-2005 by Richard
Kelsey, Jonathan Rees, and Mike Sperber.)

During program development, it is often desirable to make changes to
packages and interfaces.  In static languages, it is usually necessary
to re-compile and re-link a program in order for such changes to be
reflected in a running system.  Even in interactive Common Lisp systems,
a change to a package's exports often requires reloading clients that
have already mentioned names whose bindings change.  In those systems,
once 'read' resolves a use of a name to a symbol, that resolution is
fixed, so a change in the way that a name resolves to a symbol can be
reflected only by re-'read'ing all such references.

   The Scheme48 development environment supports rapid turnaround in
modular program development by allowing mutations to a program's
configuration and giving a clear semantics to such mutation.  The rule
is that variable bindings in a running program are always resolved
according to the current structure and interface bindings, even when
these bindings change as a result of edits to the configuration.  For
example, consider the following:

     (define-interface foo-interface (export a c))
     (define-structure foo foo-interface
       (open scheme)
       (begin (define a 1)
              (define (b x) (+ a x))
              (define (c y) (* (b a) y))))
     (define-structure bar (export d)
       (open scheme foo)
       (begin (define (d w) (+ (b w) a))))

   This program has a bug.  The variable named 'b', which is free in the
definition of 'd', has no binding in 'bar''s package.  Suppose that 'b'
was intended to be exported by 'foo', but was mistakenly omitted.  It is
not necessary to re-process 'bar' or any of 'foo''s other clients at
this point.  One need only change 'foo-interface' and inform the
development system of that change (using, say, an appropriate Emacs
command), and 'foo''s binding of 'b' will be found when the procedure
'd' is called and its reference to 'b' actually evaluated.

   Similarly, it is possible to replace a structure; clients of the old
structure will be modified so that they see bindings from the new one.
Shadowing is also supported in the same way.  Suppose that a client
package C opens a structure 'mumble' that exports a name 'x', and
'mumble''s implementation obtains the binding of 'x' from some other
structure 'frotz'.  C will see the binding from 'frotz'.  If one then
alters 'mumble' so that it shadows 'bar''s binding of 'x' with a
definition of its own, procedures in C that refer to 'x' will
subsequently automatically see 'mumble''s definition instead of the one
from 'frotz' that they saw earlier.

   This semantics might appear to require a large amount of computation
on every variable reference: the specified behaviour appears to require
scanning the package's list of opened structures and examining their
interfaces -- on every variable reference evaluated, not just at
compile-time.  However, the development environment uses caching with
cache invalidation to make variable references fast, and most of the
code is invoked only when the virtual machine traps due to a reference
to an undefined variable.

2.3.2 Listing interfaces
------------------------

The 'list-interfaces' structure provides a utility for examining
interfaces.  It is usually opened into the config package with ',config
,open list-interfaces' in order to have access to the structures &
interfaces easily.

 -- procedure: list-interface struct-or-interface --> unspecified
     Lists all of the bindings exported by STRUCT-OR-INTERFACE along
     with their static types (*note Static type system::).  For example,

          > ,config ,open list-interfaces
          > ,config (list-interface condvars)
          condvar-has-value?        (proc (:condvar) :value)
          condvar-value             (proc (:condvar) :value)
          condvar?                  (proc (:value) :boolean)
          make-condvar              (proc (&rest :value) :condvar)
          maybe-commit-and-set-condvar! (proc (:condvar :value) :boolean)
          maybe-commit-and-wait-for-condvar (proc (:condvar) :boolean)
          set-condvar-has-value?!   (proc (:condvar :value) :unspecific)
          set-condvar-value!        (proc (:condvar :value) :unspecific)


File: scheme48.info,  Node: Command processor,  Prev: Using the module system,  Up: User environment

2.4 Command processor
=====================

The Scheme48 command processor is the main development environment.  It
incorporates a read-eval-print loop as well as an interactive inspector
and debugger.  It is well-integrated with the module system for rapid
dynamic development, which is made even more convenient with the Emacs
interface, 'scheme48.el'; *note Emacs integration::.

* Menu:


* Basic commands::
* Command processor switches::
* Emacs integration commands::
* Focus value::
* Command levels::
* Module commands::
* SRFI 7::
* Debugging commands::
* Inspector::
* Command programs::
* Image-building commands::
* Resource statistics and control::


File: scheme48.info,  Node: Basic commands,  Next: Command processor switches,  Up: Command processor

2.4.1 Basic commands
--------------------

There are several generally useful commands built-in, along with many
others described in subsequent sections:

 -- command: ,help
 -- command: ,help command
 -- command: ,?
 -- command: ,? command
     Requests help on commands.  ',?' is an alias for ',help'.  Plain
     ',help' lists a synopsis of all commands available, as well as all
     switches (*note Command processor switches::).  ',help COMMAND'
     requests help on the particular command COMMAND.

 -- command: ,exit
 -- command: ,exit status
 -- command: ,exit-when-done
 -- command: ,exit-when-done status
     Exits the command processor.  ',exit' immediately exits with an
     exit status of 0.  ',exit STATUS' exits with the status that
     evaluating the expression STATUS in the interaction environment
     produces.  ',exit-when-done' is like ',exit', but it waits until
     all threads complete before exiting.

 -- command: ,go expression
     ',go' is like ',exit', except that it requires an argument, and it
     evaluates EXPRESSION in the interaction environment in a _tail
     context_ with respect to the command processor.  This means that
     the command processor may no longer be reachable by the garbage
     collector, and may be collected as garbage during the evaluation of
     EXPRESSION.  For example, the full Scheme48 command processor is
     bootstrapped from a minimal one that supports the ',go' command.
     The full command processor is initiated in an argument to the
     command, but the minimal one is no longer reachable, so it may be
     collected as garbage, leaving only the full one.

 -- command: ,run expression
     Evaluates EXPRESSION in the interaction environment.  Alone, this
     command is not very useful, but it is required in situations such
     as the inspector (*note Inspector::) and command programs (*note
     Command programs::).

 -- command: ,undefine name
     Removes the binding for NAME in the interaction environment.

 -- command: ,load filename ...
     Loads the contents each FILENAME as Scheme source code into the
     interaction environment.  Each FILENAME is translated first (*note
     Filenames::).  The given filenames may be surrounded or not by
     double-quotes; however, if a filename contains spaces, it must be
     surrounded by double-quotes.  The differences between the ',load'
     command and Scheme's 'load' procedure are that ',load' does not
     require its arguments to be quoted, allows arbitrarily many
     arguments while the 'load' procedure accepts only one filename (and
     an optional environment), and works even in environments in which
     'load' is not bound.

 -- command: ,translate from to
     A convenience for registering a filename translation without
     needing to open the 'filenames' structure.  For more details on
     filename translations, *note Filenames::; this command corresponds
     with the 'filename' structure's 'set-translation!' procedure.  As
     with ',load', each of the filenames FROM and TO may be surrounded
     or not by double-quotes, unless there is a space in the filenames,
     in which case it must be surrounded by double-quotes.

     Note that in the exec language (*note Command programs::),
     'translate' is the same as the 'filenames' structure's
     'set-translation!' procedure, _not_ the procedure named 'translate'
     from the 'filenames' structure.


File: scheme48.info,  Node: Command processor switches,  Next: Emacs integration commands,  Prev: Basic commands,  Up: Command processor

2.4.2 Switches
--------------

The Scheme48 command processor keeps track of a set of "switches",
user-settable configurations.

 -- command: ,set switch
 -- command: ,set switch {on|off|?}
 -- command: ,unset switch
 -- command: ,set ?
     ',set SWITCH' & ',set SWITCH on' set the switch SWITCH on.  ',unset
     SWITCH' & ',set SWITCH off' turn SWITCH off.  ',set SWITCH ?' gives
     a brief description of SWITCH's current status.  ',set ?' gives
     information about all the available switches and their current
     state.

   The following switches are defined.  Each switch is listed with its
name and its default status.

'ask-before-loading' _(off)_
     If this is on, Scheme48 will prompt the user before loading
     modules' code.  If it is off, it will quietly just load it.

'batch' _(off)_
     Batch mode is intended for automated uses of the command processor.
     With batch mode on, errors cause the command processor to exit, and
     the prompt is not printed.

'break-on-warnings' _(off)_
     If the 'break-on-warnings' switch is on, warnings (*note Condition
     system::) signalled that reach the command processor's handler will
     cause a command level (*note Command levels::) to be pushed,
     similarly to breakpoints and errors.

'inline-values' _(off)_
     'Inline-values' tells whether or not certain procedures may be
     integrated in-line.

'levels' _(on)_
     Errors will push a new command level (*note Command levels::) if
     this switch is on, or they will just reset back to the top level if
     'levels' is off.

'load-noisily' _(off)_
     Loading source files will cause messages to be printed if
     'load-noisily' is on; otherwise they will be suppressed.


File: scheme48.info,  Node: Emacs integration commands,  Next: Focus value,  Prev: Command processor switches,  Up: Command processor

2.4.3 Emacs integration commands
--------------------------------

There are several commands that exist mostly for Emacs integration
(*note Emacs integration::); although they may be used elsewhere, they
are not very useful or convenient without 'scheme48.el'.

 -- command: ,from-file filename
 -- command: ,end
     ',from-file FILENAME' proclaims that the code following the
     command, until an ',end' command, comes from FILENAME -- for
     example, this may be due to an appropriate Emacs command, such as
     'C-c C-l' in 'scheme48.el' --; if this is the first time the
     command processor has seen code from FILENAME, it is registered to
     correspond with the interaction environment wherein the
     ',from-file' command was used.  If it is not the first time, the
     code is evaluated within the package that was registered for
     FILENAME.

 -- command: ,forget filename
     Clears the command processor's memory of the package to which
     FILENAME corresponds.


File: scheme48.info,  Node: Focus value,  Next: Command levels,  Prev: Emacs integration commands,  Up: Command processor

2.4.4 Focus value
-----------------

The Scheme48 command processor maintains a current "focus value".  This
is typically the value that the last expression evaluated to, or a list
of values if it returned multiple values.  If it evaluated to either
zero values or Scheme48's 'unspecific' token (*note System features::),
the focus value is unchanged.  At the initial startup of Scheme48, the
focus value is set to the arguments passed to Scheme48's virtual machine
after the '-a' argument on the command-line (*note Running Scheme48::).
The focus value is accessed through the '##' syntax; the reader
substitutes a special quotation (special so that the compiler will not
generate warnings about a regular 'quote' expression containing a weird
value) for occurrences of '##'.  Several commands, such as ',inspect'
and ',dis', either accept an argument or use the current focus value.
Also, in the inspector (*note Inspector::), the focus object is the
object that is currently being inspected.

     > (cons 1 2)
     '(1 . 2)
     > ##
     '(1 . 2)
     > (begin (display "Hello, world!") (newline))
     Hello, world!
     > ##
     '(1 . 2)
     > (cdr ##)
     2
     > (define x 5)
     ; no values returned
     > (+ ## x)
     7
     > (values 1 2 3)
     ; 3 values returned
     1
     2
     3
     > ##
     '(1 2 3)


File: scheme48.info,  Node: Command levels,  Next: Module commands,  Prev: Focus value,  Up: Command processor

2.4.5 Command levels
--------------------

The Scheme48 command processor maintains a stack of "command levels", or
recursive invocations of the command processor.  Each command level
retains information about the point from the previous command level at
which it was pushed: the threads that were running -- which the command
processor suspends --, including the thread of that command level
itself; the continuation of what pushed the level; and, if applicable,
the condition (*note Condition system::) that caused the command level
to be pushed.  Each command level has its own thread scheduler, which
controls all threads running at that level, including those threads'
children.

   Some beginning users may find command levels confusing, particularly
those who are new to Scheme or who are familiar with the more simplistic
interaction methods of other Scheme systems.  These users may disable
the command level system with the 'levels' switch (*note Command
processor switches::) by writing the command ',set levels off'.

 -- command: ,push
 -- command: ,pop
 -- command: ,resume
 -- command: ,resume level
 -- command: ,reset
 -- command: ,reset level
     ',push' pushes a new command level.  ',pop' pops the current
     command level.  'C-d'/'^D', or EOF, has the same effect as the
     ',pop' command.  Popping the top command level inquires the user
     whether to exit or to return to the top level.  ',resume LEVEL'
     pops all command levels down to LEVEL and resumes all threads that
     were running at LEVEL when it was suspended to push another command
     level.  ',reset LEVEL' resets the command processor to LEVEL,
     terminating all threads at that level but the command reader
     thread.  ',resume' & ',reset' with no argument use the top command
     level.

 -- command: ,condition
 -- command: ,threads
     ',condition' sets the focus value to the condition that caused the
     command level to be pushed, or prints 'no condition' if there was
     no relevant condition.  ',threads' invokes the inspector on the
     list of threads of the previous command level, or on nothing if the
     current command level is the top one.

     > ,push
     1> ,push
     2> ,pop
     1> ,reset

     Top level
     > ,open threads formats
     > ,push
     1> ,push
     2> (spawn (lambda ()
                 (let loop ()
                   (sleep 10000)    ; Sleep for ten seconds.
                   (format #t "~&foo~%")
                   (loop)))
               'my-thread)
     2>
     foo
     ,push
     3> ,threads
     ; 2 values returned
      [0] '#{Thread 4 my-thread}
      [1] '#{Thread 3 command-loop}
     3: q
     '(#{Thread 4 my-thread} #{Thread 3 command-loop})
     3> ,resume 1

     foo
     2>
     foo
     ,push
     3> ,reset 1
     Back to 1> ,pop
     >


File: scheme48.info,  Node: Module commands,  Next: SRFI 7,  Prev: Command levels,  Up: Command processor

2.4.6 Module commands
---------------------

Scheme48's command processor is well-integrated with its module system
(*note Module system::).  It has several dedicated environments,
including the user package and the config package, and can be used to
evaluate code within most packages in the Scheme48 image during program
development.  The config package includes bindings for Scheme48's
configuration language; structure & interface definitions may be
evaluated in it.  The command processor also has provisions to support
rapid development and module reloading by automatically updating
references to redefined variables in compiled code without having to
reload all of that code.

 -- command: ,open struct ...
     Opens each STRUCT into the interaction environment, making all of
     its exported bindings available.  This may have the consequence of
     loading code to implement those bindings.  If there was code
     evaluated in the interaction environment that referred to a
     previously undefined variable for whose name a binding was exported
     by one of these structures, a message is printed to the effect that
     that binding is now available, and the code that referred to that
     undefined variable will be modified to subsequently refer to the
     newly available binding.

 -- command: ,load-package struct
 -- command: ,reload-package struct
     ',load-package' and ',reload-package' both load the code associated
     with the package underlying STRUCT, after ensuring that all of the
     other structures opened by that package are loaded as well.
     ',load-package' loads the code only if has not already been loaded;
     ',reload-package' unconditionally loads it.

 -- command: ,user
 -- command: ,user command-or-exp
 -- command: ,config
 -- command: ,config command-or-exp
 -- command: ,for-syntax
 -- command: ,for-syntax command-or-exp
 -- command: ,new-package
 -- command: ,in structure
 -- command: ,in structure command-or-exp
     These all operate on the interaction environment.  ',user' sets it
     to the user package, which is the default at initial startup.
     ',user COMMAND-OR-EXP' temporarily sets the interaction environment
     to the user package, processes COMMAND-OR-EXP, and reverts the
     interaction environment to what it was before ',user' was invoked.
     The ',config' & ',for-syntax' commands are similar, except that
     they operate on the config package and the package used for the
     user package's macros (*note Macros in concert with modules::).
     ',new-package' creates a temporary, unnamed package with a vanilla
     R5RS environment and sets the interaction environment to it.  That
     new package is not accessible in any way except to the user of the
     command processor, and it is destroyed after the user switches to
     another environment (unless the user uses the ',structure' command;
     see below).  ',in STRUCTURE' sets the interaction environment to be
     STRUCTURE's package; STRUCTURE is a name whose value is extracted
     from the config package.  ',in STRUCTURE COMMAND-OR-EXP' sets the
     interaction environment to STRUCTURE temporarily to process
     COMMAND-OR-EXP and then reverts it to what it was before the use of
     ',in'.  Note that, within a structure, the bindings available are
     exactly those bindings that would be available within the
     structure's static code, i.e. code in the structure's 'begin'
     package clauses or code in files referred to by 'files' package
     clauses.

 -- command: ,user-package-is struct
 -- command: ,config-package-is struct
     ',user-package-is' & ',config-package-is' set the user & config
     packages, respectively, to be STRUCT's package.  STRUCT is a name
     whose value is accessed from the current config package.

 -- command: ,structure name interface
     This defines a structure named NAME in the config package that is a
     view of INTERFACE on the current interaction environment.


File: scheme48.info,  Node: SRFI 7,  Next: Debugging commands,  Prev: Module commands,  Up: Command processor

2.4.7 SRFI 7
------------

Scheme48 supports [SRFI 7] after loading the 'srfi-7' structure by
providing two commands for loading [SRFI 7] programs:

 -- command: ,load-srfi-7-program name filename
 -- command: ,load-srfi-7-script name filename
     These load [SRFI 7] a program into a newly constructed structure,
     named NAME, which opens whatever other structures are needed by
     features specified in the program.  ',load-srfi-7-program' loads a
     simple [SRFI 7] program; ',load-srfi-7-script' skips the first
     line, intended for [SRFI 22] Unix scripts.


File: scheme48.info,  Node: Debugging commands,  Next: Inspector,  Prev: SRFI 7,  Up: Command processor

2.4.8 Debugging commands
------------------------

There are a number of commands useful for debugging, along with a
continuation inspector, all of which composes a convenient debugger.

 -- command: ,bound? name
 -- command: ,where
 -- command: ,where procedure
     ',bound?' prints out binding information about NAME, if it is bound
     in the interaction environment, or 'Not bound' if NAME is unbound.
     ',where' prints out information about what file and package its
     procedure argument was created in.  If PROCEDURE is not passed,
     ',where' uses the focus value.  If ',where''s argument is not a
     procedure, it informs the user of this fact.  If ',where' cannot
     find the location of its argument's creation, it prints 'Source
     file not recorded.'

 -- command: ,expand
 -- command: ,expand exp
 -- command: ,dis
 -- command: ,dis proc
     ',expand' prints out a macro-expansion of EXP, or the focus value
     if EXP is not provided.  The expression to be expanded should be an
     ordinary S-expression.  The expansion may contain 'generated names'
     and 'qualified names.'  These merely contain lexical context
     information that allow one to differentiate between identifiers
     with the same name.  Generated names look like '#{Generated NAME
     UNIQUE-NUMERIC-ID}'.  Qualified names appear to be vectors; they
     look like '#(>> INTRODUCER-MACRO NAME UNIQUE-NUMERIC-ID)', where
     INTRODUCER-MACRO is the macro that introduced the name.

     ',dis' prints out a disassembly of its procedure, continuation, or
     template argument.  If PROC is passed, it is evaluated in the
     interaction environment; if not, ',dis' disassembles the focus
     value.  The disassembly is of Scheme48's virtual machine's byte
     code.(1)

 -- command: ,condition
 -- command: ,threads
     For the descriptions of these commands, *note Command levels::.
     These are mentioned here because they are relevant in the context
     of debugging.

 -- command: ,trace
 -- command: ,trace name ...
 -- command: ,untrace
 -- command: ,untrace name ...
     Traced procedures will print out information about when they are
     entered and when they exit.  ',trace' lists all of the traced
     procedures' bindings.  ',trace NAME ...' sets each NAME in the
     interaction environment, which should be bound to a procedure, to
     be a traced procedure over the original procedure.  ',untrace'
     resets all traced procedures to their original, untraced
     procedures.  ',untrace NAME ...' untraces each individual traced
     procedure of NAME ... in the interaction environment.

 -- command: ,preview
     Prints a trace of the previous command level's suspended
     continuation.  This is analogous with stack traces in many
     debuggers.

 -- command: ,debug
     Invokes the debugger: runs the inspector on the previous command
     level's saved continuation.  For more details, *note Inspector::.

 -- command: ,proceed
 -- command: ,proceed exp
     Returns to the continuation of the condition signalling of the
     previous command level.  Only certain kinds of conditions will push
     a new command level, however -- breakpoints, errors, and
     interrupts, and, if the 'break-on-warnings' switch is on, warnings
     --; also, certain kinds of errors that do push new command levels
     do not permit being proceeded from.  In particular, only with a few
     VM primitives may the ',proceed' command be used.  If EXP is
     passed, it is evaluated in the interaction environment to produce
     the values to return; if it is not passed, zero values are
     returned.

   ---------- Footnotes ----------

   (1) A description of the byte code is forthcoming, although it does
not have much priority to this manual's author.  For now, users can read
the rudimentary descriptions of the Scheme48 virtual machine's byte code
instruction set in 'vm/interp/arch.scm' of Scheme48's Scheme source.


File: scheme48.info,  Node: Inspector,  Next: Command programs,  Prev: Debugging commands,  Up: Command processor

2.4.9 Inspector
---------------

Scheme48 provides a simple interactive object inspector.  The command
processor's prompt's end changes from '>' to ':' when in inspection
mode.  The inspector is the basis of the debugger, which is, for the
most part, merely an inspector of continuations.  In the debugger, the
prompt is 'debug:'.  In the inspector, objects are printed followed by
menus of their components.  Entries in the menu are printed with the
index, which optionally includes a symbolic name, and the value of the
component.  For example, a pair whose car is the symbol 'a' and whose
cdr is the symbol 'b' would be printed by the inspector like this:

     '(a . b)

      [0: car] 'a
      [1: cdr] 'b

   The inspector maintains a stack of the focus objects it previously
inspected.  Selecting a new focus object pushes the current one onto the
stack; the 'u' command pops the stack.

 -- command: ,inspect
 -- command: ,inspect exp
     Invokes the inspector.  If EXP is present, it is evaluated in the
     user package and its result is inspected (or a list of results, if
     it returned multiple values, is inspected).  If EXP is absent, the
     current focus value is inspected.

   The inspector operates with its own set of commands, separate from
the regular interaction commands, although regular commands may be
invoked from the inspector as normal.  Inspector commands are entered
with or without a preceding comma at the inspector prompt.  Multiple
inspector commands may be entered on one line; an input may also consist
of an expression to be evaluated.  If an expression is evaluated, its
value is selected as the focus object.  Note, however, that, since
inspector commands are symbols, variables cannot be evaluated just by
entering their names; one must use either the ',run' command or wrap the
variables in a 'begin'.

   These inspector commands are defined:

 -- inspector command: menu
 -- inspector command: m
     'Menu' prints a menu for the focus object.  'M' moves forward in
     the current menu if there are more than sixteen items to be
     displayed.

 -- inspector command: u
     Pops the stack of focus objects, discarding the current one and
     setting the focus object to the current top of the stack.

 -- inspector command: q
     Quits the inspector, going back into the read-eval-print loop.

 -- inspector command: template
     Attempts to coerce the focus object into a template.  If
     successful, this selects it as the new focus object; if not, this
     prints an error to that effect.  Templates are the static
     components of closures and continuations: they contain the code for
     the procedure, the top-level references made by the procedure,
     literal constants used in the code, and any inferior templates of
     closures that may be constructed by the code.

 -- inspector command: d
     Goes down to the parent of the continuation being inspected.  This
     command is valid only in the debugger mode, i.e. when the focus
     object is a continuation.


File: scheme48.info,  Node: Command programs,  Next: Image-building commands,  Prev: Inspector,  Up: Command processor

2.4.10 Command programs
-----------------------

The Scheme48 command processor can be controlled programmatically by
"command programs", programs written in the "exec language".  This
language is essentially a mirror of the commands but in a syntax using
S-expressions.  The language also includes all of Scheme.  The exec
language is defined as part of the "exec package".

 -- command: ,exec
 -- command: ,exec command
     Sets the interaction environment to be the exec package.  If an
     argument is passed, it is set temporarily, only to run the given
     command.

   Commands in the exec language are invoked as procedures in Scheme.
Arguments should be passed as follows:

   * Identifiers, such as those of structure names in the config
     package, should be passed as literal symbols.  For instance, the
     command ',in frobbotz' would become in the exec language '(in
     'frobbotz)'.

   * Filenames should be passed as strings; e.g., ',dump frob.image'
     becomes '(dump "frob.image")'.

   * Commands should be represented in list values with the car being
     the command name and the cdr being the arguments.  Note that when
     applying a command an argument that is a command invocation is
     often quoted to produce a list, but the list should not include any
     quotation; for instance, ',in mumble ,undefine frobnicate' would
     become '(in 'mumble '(undefine frobnicate))', even though simply
     ',undefine frobnicate' would become '(undefine 'frobnicate)'.

     The reason for this is that the command invocation in the exec
     language is different from a list that represents a command
     invocation passed as an argument to another command; since commands
     in the exec language are ordinary procedures, the arguments must be
     quoted, but the quoted arguments are not themselves evaluated: they
     are applied as commands.

     An argument to a command that expects a command invocation can also
     be a procedure, which would simply be called with zero arguments.
     For instance, '(config (lambda () (display
     (interaction-environment)) (newline)))' will call the given
     procedure with the interaction environment set to the config
     package.

   * Expressions must be passed using the 'run' command.  For example,
     the equivalent of ',user (+ 1 2)' in the exec language would be
     '(user '(run (+ 1 2)))'.

   Command programs can be loaded by running the ',load' command in the
exec package.  Scripts to load application bundles are usually written
in the exec language and loaded into the exec package.  For example,
this command program, when loaded into the exec package, will load
'foo.scm' into the config package, ensure that the package 'frobbotzim'
is loaded, and open the 'quuxim' structure in the user package:

     (config '(load "foo.scm"))
     (load-package 'frobbotzim)
     (user '(open quuxim))


File: scheme48.info,  Node: Image-building commands,  Next: Resource statistics and control,  Prev: Command programs,  Up: Command processor

2.4.11 Image-building commands
------------------------------

Since Scheme48's operation revolves about an image-based model, these
commands provide a way to save heap images on the file system, which may
be resumed by invoking the Scheme48 virtual machine on them as in *note
Running Scheme48::.

 -- command: ,build resumer filename
 -- command: ,dump filename
 -- command: ,dump filename message
     ',build' evaluates RESUMER, whose value should be a unary
     procedure, and builds a heap image in FILENAME that, when resumed
     by the virtual machine, will pass the resumer all of the
     command-line arguments after the '-a' argument to the virtual
     machine.  The run-time system will have been initialized as with
     usual resumers (*note Suspending and resuming heap images::), and a
     basic condition handler will have been installed by the time that
     the resumer is called.  On Unix, RESUMER must return an integer
     exit status for the process.  ',dump' dumps the Scheme48 command
     processor, including all of the current settings, to FILENAME.  If
     MESSAGE is passed, it should be a string delimited by
     double-quotes, and it will be printed as part of the welcome banner
     on startup; its default value, if it is not present, is
     '"(suspended image)"'.


File: scheme48.info,  Node: Resource statistics and control,  Prev: Image-building commands,  Up: Command processor

2.4.12 Resource statistics and control
--------------------------------------

Scheme48 provides several devices for querying statistics about various
resources and controlling resources, both in the command processor and
programmatically.

 -- command: ,collect
     Forces a garbage collection and prints the amount of space in the
     heap before and after the collection.

 -- command: ,time expression
     Evaluates EXPRESSION and prints how long it took.  Three numbers
     are printed: run time, GC time, and real time.  The run time is the
     amount of time in Scheme code; the GC time is the amount of time
     spent in the garbage collector; and the real time is the actual
     amount of time that passed during the expression's evaluation.

 -- command: ,keep
 -- command: ,keep kind ...
 -- command: ,flush
 -- command: ,flush kind ...
     Scheme48 maintains several different kinds of information used for
     debugging information.  ',keep' with no arguments shows what kinds
     of debugging data are preserved and what kinds are not.  ',keep
     KIND ...' requests that the debugging data of the given kinds
     should be kept; the ',flush' command requests the opposite.
     ',flush' with no arguments flushes location names and resets the
     debug data table.  The following are the kinds of debugging data:

     'names'
          procedure names
     'maps'
          environment maps used by the debugger to show local variable
          names
     'files'
          filenames where procedures were defined
     'source'
          source code surrounding continuations, printed by the debugger
     'tabulate'
          if true, will store debug data records in a global table that
          can be easily flushed; if false, will store directly in
          compiled code

     ',flush' can also accept 'location-names', which will flush the
     table of top-level variables' names (printed, for example, by the
     ',bound?' command); 'file-packages', which will flush the table
     that maps filenames to packages in which code from those files
     should be evaluated; or 'table', in which case the table of debug
     data is flushed.

     Removing much debug data can significantly reduce the size of
     Scheme48 heap images, but it can also make error messages and
     debugging much more difficult.  Usually, all debug data is
     retained; only for images that must be small and that do not need
     to be debuggable should the debugging data flags be turned off.

   The 'spatial' structure exports these utilities for displaying
various statistics about the heap:

 -- procedure: space --> unspecified
 -- procedure: vector-space [predicate] --> unspecified
 -- procedure: record-space [predicate] --> unspecified
     'Space' prints out a list of the numbers of all objects and the
     number of bytes allocated for those objects on the heap,
     partitioned by the objects' primitive types and whether or not they
     are immutable (pure) or mutable (impure).  'Vector-space' prints
     the number of vectors and the number of bytes used to store those
     vectors of several different varieties, based on certain heuristics
     about their form.  If the predicate argument is passed, it gathers
     only vectors that satisfy that predicate.  'Record-space' prints
     out, for each record type in the heap, both the number of all
     instances of that record type and the number of bytes used to store
     all of those instances.  Like 'vector-space', if the predicate
     argument is passed, 'record-space' will consider only those records
     that satisfy the predicate.

     All of these three procedures first invoke the garbage collector
     before gathering statistics.

   The 'traverse' structure provides a simple utility for finding paths
by which objects refer to one another.

 -- procedure: traverse-breadth-first object --> unspecified
 -- procedure: traverse-depth-first object --> unspecified
     These traverse the heap, starting at OBJECT, recording all objects
     transitively referred to.  'Traverse-breadth-first' uses a
     FIFO-queue-directed breadth-first graph traversal, while
     'traverse-depth-first' uses a LIFO-stack-directed depth-first graph
     traversal.  The traversal halts at any leaves in the graph, which
     are distinguished by an internal "leaf predicate" in the module.
     See below on 'set-leaf-predicate!' on how to customize this and
     what the default is.

     The traversal information is recorded in a global resource; it is
     not thread-safe, and intended only for interactive usage.  The
     record can be reset by passing some simple object with no
     references to either 'traverse-breadth-first' or
     'traverse-depth-first'; e.g., '(traverse-depth-first #f)'.

 -- procedure: trail object --> unspecified
     After traversing the heap from an initial object, '(trail OBJECT)'
     prints the path of references and intermediate objects by which the
     initial object holds a transitive reference to OBJECT.

 -- procedure: set-leaf-predicate! predicate --> unspecified
 -- procedure: usual-leaf-predicate object --> boolean
     'Set-leaf-predicate!' sets the current leaf predicate to be
     PREDICATE.  'Usual-leaf-predicate' is the default leaf predicate;
     it considers simple numbers (integers and flonums), strings, byte
     vectors, characters, and immediate objects (true, false, nil, and
     the unspecific object) to be leaves, and everything else to be
     branches.


File: scheme48.info,  Node: Module system,  Next: System facilities,  Prev: User environment,  Up: Top

3 Module system
***************

Scheme48 has an advanced module system that is designed to interact well
with macros, incremental compilation, and the interactive development
environment's (*note User environment::) code reloading facilities for
rapid program development.  For details on the integration of the module
system and the user environment for rapid code reloading, *note Using
the module system::.

* Menu:

* Module system architecture::
* Module configuration language::	Language of the module system
* Macros in concert with modules::
* Static type system::


File: scheme48.info,  Node: Module system architecture,  Next: Module configuration language,  Up: Module system

3.1 Module system architecture
==============================

The fundamental mechanism by which Scheme code is evaluated is the
lexical environment.  Scheme48's module system revolves around this
fundamental concept.  Its purpose is to control the denotation of names
in code(1) in a structured, modular manner.  The module system is
manipulated by a static "configuration language", described in the next
section; this section describes the concepts in the architecture of the
module system.

   The "package" is the entity internal to the module system that maps a
set of names to denotations.  For example, the package that represents
the Scheme language maps 'lambda' to a descriptor for the special form
that the compiler interprets to construct a procedure, 'car' to the
procedure that accesses the car of a pair, &c.  Packages are not
explicitly manipulated by the configuration language, but they lie
underneath structures, which are described below.  A package also
contains the code of a module and controls the visibility of names
within that code.  It also includes some further information, such as
optimizer switches.  A "structure" is a view on a package; that is, it
contains a package and an "interface" that lists all of the names it
exports to the outside.  Multiple structures may be constructed atop a
single package; this mechanism is often used to offer multiple
abstraction levels to the outside.  A "module" is an abstract entity: it
consists of some code, the namespace visible to the code, and the set of
abstractions or views upon that code.

   A package contains a list of the structures whose bindings should be
available in the code of that package.  If a structure is referred to in
a such a list of a package, the package is said to "open" that
structure.  It is illegal for a package to open two structures whose
interfaces contain the same name.(2)  Packages may also modify the names
of the bindings that they import.  They may import only selected
bindings, exclude certain bindings from structures, rename imported
bindings, create alias bindings, and add prefixes to names.

   Most packages will open the standard 'scheme' structure, although it
is not implicitly opened, and the module system allows not opening
'scheme'.  It may seem to be not very useful to not open it, but this is
necessary if some bindings from it are intended to be shadowed by
another structure, and it allows for entirely different languages from
Scheme to be used in a package's code.  For example, Scheme48's byte
code interpreter virtual machine is implemented in a subset of Scheme
called Pre-Scheme, which is described in a later chapter in this manual.
The modules that compose the VM all open not the 'scheme' structure but
the _'prescheme'_ structure.  The configuration language itself is
controlled by the module system, too.  In another example, from Scsh,
the Scheme shell, there is a structure 'scsh' that contains all of the
Unix shell programming facilities.  However, the 'scsh' structure
necessarily modifies some of the bindings related to I/O that the
'scheme' structure exports.  Modules could not open both 'scheme' and
'scsh', because they both provide several bindings with the same names,
so Scsh defines a more convenient 'scheme-with-scsh' structure that
opens both 'scheme', but with all of the shadowed bindings excluded, and
'scsh'; modules that use Scsh would open neither 'scsh' nor 'scheme':
they instead open just 'scheme-with-scsh'.

   Interfaces are separated from structures in order that they may be
reüsed and combined.  For example, several different modules may
implement the same abstractions differently.  The structures that they
include would, in such cases, reüse the same interfaces.  Also, it is
sometimes desirable to combine several interfaces into a "compound
interface"; see the 'compound-interface' form in the next section.
Furthermore, during interactive development, interface definitions may
be reloaded, and the structures that use them will automatically begin
using the new interfaces; *note Using the module system::.

   Scheme48's module system also supports "parameterized modules".
Parameterized modules, sometimes known as "generic modules",
"higher-order modules" or "functors", are essentially functions at the
module system level that map structures to structures.  They may be
instantiated or applied arbitrarily many times, and they may accept and
return arbitrarily many structures.  Parameterized modules may also
accept and return other parameterized modules.

   ---------- Footnotes ----------

   (1) This is in contrast to, for example, Common Lisp's package
system, which controls the mapping from strings to names.

   (2) The current implementation, however, does not detect this.
Instead it uses the left-most structure in the list of a package's
'open' clause; see the next section for details on this.


File: scheme48.info,  Node: Module configuration language,  Next: Macros in concert with modules,  Prev: Module system architecture,  Up: Module system

3.2 Module configuration language
=================================

Scheme48's module system is used through a "module configuration
language".  _The configuration language is entirely separate from
Scheme._  Typically, in one configuration, or set of components that
compose a program, there is an 'interfaces.scm' file that defines all of
the interfaces used by the configuration, and there is also a
'packages.scm' file that defines all of the packages & structures that
compose it.  Note that modules are not necessarily divided into files or
restricted to one file: modules may include arbitrarily many files, and
modules' code may also be written in-line to structure expressions (see
the 'begin' package clause below), although that is usually only for
expository purposes and trivial modules.

   Structures are always created with corresponding "package clauses".
Each clause specifies an attribute of the package that underlies the
structure or structures created using the clauses.  There are several
different types of clauses:

 -- package clause: open structure ...
 -- package clause: access structure ...
     'Open' specifies that the package should open each of the listed
     structures, whose packages will be loaded if necessary.  'Access'
     specifies that each listed structure should be accessible using the
     '(structure-ref STRUCTURE IDENTIFIER)' special form, which
     evaluates to the value of IDENTIFIER exported by the accessed
     structure STRUCTURE.  'Structure-ref' is available from the
     'structure-refs' structure.  Each STRUCTURE passed to 'access' is
     not opened, however; the bindings exported thereby are available
     only using 'structure-ref'.  While the qualified 'structure-ref'
     mechanism is no longer useful in the presence of modified
     structures (see below on 'modify', 'subset', & 'with-prefix'), some
     old code still uses it, and 'access' is also useful to force that
     the listed structures' packages be loaded without cluttering the
     namespace of the package whose clauses the 'access' clause is
     among.

 -- package clause: for-syntax package-clause ...
     Specifies a set of package clauses for the next floor of the
     reflective tower; *note Macros in concert with modules::.

 -- package clause: files file-specifier ...
 -- package clause: begin code ...
     'Files' and 'begin' specify the package's code.  'Files' takes a
     sequence of namelists for the filenames of files that contain code;
     *note Filenames::.  'Begin' accepts in-line program code.

 -- package clause: optimize optimizer-specifier ...
 -- package clause: integrate [on?]
     'Optimize' clauses request that specified compiler optimizers be
     applied to the code.  (Actually, 'optimizer' is a misnomer.  The
     'optimize' clause may specify arbitrary passes that the compiler
     can be extended with.)  'Integrate' clauses specify whether or not
     integrable procedures from other modules, most notably Scheme
     primitives such as 'car' or 'vector-ref', should actually be
     integrated in this package.  This is by default on.  Most modules
     should leave it on for any reasonable performance; only a select
     few, into which code is intended to be dynamically loaded
     frequently and in which redefinition of imported procedures is
     common, need turn this off.  The value of the argument to
     'integrate' clauses should be a literal boolean, i.e. '#t' or '#f';
     if no argument is supplied, integration is enabled by default.

     Currently, the only optimizer built-in to Scheme48 is the automatic
     procedure integrator, or 'auto-integrate', which attempts stronger
     type reconstruction than is attempted with most code (*note Static
     type system::) and selects procedures below a certain size to be
     made integrable (so that the body will be compiled in-line in all
     known call sites).  Older versions of Scheme48 also provided
     another optimizer, 'flat-environments', which would flatten certain
     lexical closure environments, rather than using a nested
     environment structure.  Now, however, Scheme48's byte code compiler
     always flattens environments; specifying 'flat-environments' in an
     'optimize' clause does nothing.

   A configuration is a sequence of definitions.  There are definition
forms for only structures and interfaces.

 -- configuration form: define-structure name interface package-clause
          ...
 -- configuration form: define-structures ((name interface) ...)
          package-clause ...
     'Define-structure' creates a package with the given package clauses
     and defines NAME to be the single view atop it, with the interface
     INTERFACE.  'Define-structures' also creates a package with the
     given package clauses; upon that package, it defines each NAME to
     be a view on it with the corresponding interface.

 -- configuration form: define-module (name parameter ...) definition
          ... result
 -- configuration form: def name ... (parameterized-module argument ...)
     'Define-module' defines NAME to be a parameterized module that
     accepts the given parameters.

 -- configuration form: define-interface name interface
     Defines NAME to be the interface that INTERFACE evaluates to.
     INTERFACE may either be an interface constructor application or
     simply a name defined to be an interface by some prior
     'define-interface' form.

 -- interface constructor: export export-specifier ...
     'Export' constructs a simple interface with the given export
     specifiers.  The export specifiers specify names to export and
     their corresponding static types.  Each EXPORT-SPECIFIER should
     have one of the following forms:

     'SYMBOL'
          in which case SYMBOL is exported with the most general value
          type;

     '(SYMBOL TYPE)'
          in which case SYMBOL is exported with the given type; or

     '((SYMBOL ...) TYPE)'
          in which case each SYMBOL is exported with the same given type

     For details on the valid forms of TYPE, *note Static type system::.
     *Note:* All macros listed in interfaces _must_ be explicitly
     annotated with the type ':syntax'; otherwise they would be exported
     with a Scheme value type, which would confuse the compiler, because
     it would not realize that they are macros: it would instead treat
     them as ordinary variables that have regular run-time values.

 -- interface constructor: compound-interface interface ...
     This constructs an interface that contains all of the export
     specifiers from each INTERFACE.

   Structures may also be constructed anonymously; this is typically
most useful in passing them to or returning them from parameterized
modules.

 -- structure constructor: structure interface package-clauses
 -- structure constructor: structures (interface ...) package-clauses
     'Structure' creates a package with the given clauses and evaluates
     to a structure over it with the given interface.  'Structures' does
     similarly, but it evaluates to a number of structures, each with
     the corresponding INTERFACE.

 -- structure constructor: subset structure (name ...)
 -- structure constructor: with-prefix structure name
 -- structure constructor: modify structure modifier ...
     These modify the interface of STRUCTURE.  'Subset' evaluates to a
     structure that exports only NAME ..., excluding any other names
     that STRUCTURE exported.  'With-prefix' adds a prefix NAME to every
     name listed in STRUCTURE's interface.  Both 'subset' and
     'with-prefix' are syntactic sugar for the more general 'modify',
     which applies the modifier commands in a strictly right-to-left or
     last-to-first order.  *Note:* These all _denote new structures with
     new interfaces_; they do not destructively modify existing
     structures' interfaces.

 -- modifier command: prefix name
 -- modifier command: expose name ...
 -- modifier command: hide name ...
 -- modifier command: alias (from to) ...
 -- modifier command: rename (from to) ...
     'Prefix' adds the prefix NAME to every exported name in the
     structure's interface.  'Expose' exposes only NAME ...; any other
     names are hidden.  'Hide' hides NAME ....  'Alias' exports each TO
     as though it were the corresponding FROM, as well as each FROM.
     'Rename' exports each TO as if it were the corresponding FROM, but
     it also hides the corresponding FROM.

     Examples:

          (modify STRUCTURE
                  (prefix foo:)
                  (expose bar baz quux))

     makes only 'foo:bar', 'foo:baz', and 'foo:quux', available.

          (modify STRUCTURE
                  (hide baz:quux)
                  (prefix baz:)
                  (rename (foo bar)
                          (mumble frotz))
                  (alias (gargle mumph)))

     exports 'baz:gargle' as what was originally 'mumble', 'baz:mumph'
     as an alias for what was originally 'gargle', 'baz:frotz' as what
     was originally 'mumble', 'baz:bar' as what was originally 'foo',
     _not_ 'baz:quux' -- what was originally simply 'quux' --, and
     everything else that STRUCTURE exported, but with a prefix of
     'baz:'.

   There are several simple utilities for binding variables to
structures locally and returning multiple structures not necessarily
over the same package (i.e. not with 'structures').  These are all valid
in the bodies of 'define-module' and 'def' forms, and in the arguments
to parameterized modules and 'open' package clauses.

 -- syntax: begin body
 -- syntax: let ((name value) ...) body
 -- syntax: receive (name ...) producer body
 -- syntax: values value ...
     These are all as in ordinary Scheme.  Note, however, that there is
     no reasonable way by which to use 'values' except to call it, so it
     is considered a syntax; also note that 'receive' may not receive a
     variable number of values -- i.e. there are no 'rest lists' --,
     because list values in the configuration language are nonsensical.

   Finally, the configuration language also supports syntactic
extensions, or macros, as in Scheme.

 -- configuration form: define-syntax name transformer-specifier
     Defines the syntax transformer NAME to be the transformer specified
     by TRANSFORMER-SPECIFIER.  TRANSFORMER-SPECIFIER is exactly the
     same as in Scheme code; it is evaluated as ordinary Scheme.


File: scheme48.info,  Node: Macros in concert with modules,  Next: Static type system,  Prev: Module configuration language,  Up: Module system

3.3 Macros in concert with modules
==================================

One reason that the standard Scheme language does not support a module
system yet is the issue of macros and modularity.  There are several
issues to deal with:

   * that compilation of code that uses macros requires presence of
     those macros' definitions, which prevents true separate
     compilation, because those macros may be from other modules;

   * that a macro's expansion must preserve referential transparency and
     hygiene, for example in cases where it refers to names from within
     the module in which it was defined, even if those names weren't
     exported; and

   * that a macro's code may be arbitrary Scheme code, which in turn can
     use other modules, so one module's compile-time, when macros are
     expanded, is another's run-time, when the code used in macros is
     executed by the expander: this makes a tower of phases of code
     evaluation over which some coherent control must be provided.

Scheme48's module system tries to address all of these issues coherently
and comprehensively.  Although it cannot offer _total_ separate
compilation, it can offer incremental compilation, and compiled modules
can be dumped to the file system & restored in the process of
incremental compilation.(1)

   Scheme48's module system is also very careful to preserve non-local
module references from a macro's expansion.  Macros in Scheme48 are
required to perform hygienic renaming in order for this preservation,
however; *note Explicit renaming macros::.  For a brief example,
consider the 'delay' syntax for lazy evaluation.  It expands to a simple
procedure call:

     (delay EXPRESSION)
       ==> (make-promise (lambda () EXPRESSION))

However, 'make-promise' is not exported from the 'scheme' structure.
The expansion works correctly due to the hygienic renaming performed by
the 'delay' macro transformer: when it hygienically renames
'make-promise', the output contains not the symbol but a special token
that refers exactly to the binding of 'make-promise' from the
environment in which the 'delay' macro transformer was defined.  Special
care is taken to preserve this information.  Had 'delay' expanded to a
simple S-expression with simple symbols, it would have generated a free
reference to 'make-promise', which would cause run-time undefined
variable errors, or, if the module in which 'delay' was used had its
_own_ binding of or imported a binding of the name 'make-promise',
'delay''s expansion would refer to the wrong binding, and there could
potentially be drastic and entirely unintended impact upon its
semantics.

   Finally, Scheme48's module system has a special design for the tower
of phases, called a "reflective tower".(2)  Every storey represents the
environment available at successive macro levels.  That is, when the
right-hand side of a macro definition or binding is evaluated in an
environment, the next storey in that environment's reflective tower is
used to evaluate that macro binding.  For example, in this code, there
are two storeys used in the tower:

     (define (foo ...bar...)
       (let-syntax ((baz ...quux...))
         ...zot...))

In order to evaluate code in one storey of the reflective tower, it is
necessary to expand all macros first.  Most of the code in this example
will eventually be evaluated in the first storey of the reflective tower
(assuming it is an ordinary top-level definition), but, in order to
expand macros in that code, the 'let-syntax' must be expanded.  This
causes '...quux...' to be evaluated in the _second_ storey of the tower,
after which macro expansion can proceed, and long after which the
enclosing program can be evaluated.

   The module system provides a simple way to manipulate the reflective
tower.  There is a package clause, 'for-syntax', that simply contains
package clauses for the next storey in the tower.  For example, a
package with the following clauses:

     (open scheme foo bar)
     (for-syntax (open scheme baz quux))

has all the bindings of 'scheme', 'foo', & 'bar', at the ground storey;
and the environment in which macros' definitions are evaluated provides
everything from 'scheme', 'baz', & 'quux'.

   With no 'for-syntax' clauses, the 'scheme' structure is implicitly
opened; however, if there are 'for-syntax' clauses, 'scheme' must be
explicitly opened.(3)  Also, 'for-syntax' clauses may be arbitrarily
nested: reflective towers are theoretically infinite in height.  (They
are internally implemented lazily, so they grow exactly as high as they
need to be.)

   Here is a simple, though contrived, example of using 'for-syntax'.
The 'while-loops' structure exports 'while', a macro similar to C's
'while' loop.  'While''s transformer unhygienically binds the name
'exit' to a procedure that exits from the loop.  It necessarily,
therefore, uses explicit renaming macros (*note Explicit renaming
macros::) in order to break hygiene; it also, in the macro transformer,
uses the 'destructure' macro to destructure the input form (*note
Library utilities::, in particular, the structure 'destructuring' for
destructuring S-expressions).

     (define-structure while-loops (export while)
       (open scheme)
       (for-syntax (open scheme destructuring))
       (begin
         (define-syntax while
           (lambda (form r compare)
             (destructure (((WHILE test . body) form))
               `(,(r 'CALL-WITH-CURRENT-CONTINUATION)
                  (,(r 'LAMBDA) (EXIT)
                    (,(r 'LET) (r 'LOOP) ()
                      (,(r 'IF) ,test
                        (,(r 'BEGIN)
                          ,@body
                          (,(r 'LOOP)))))))))
           (CALL-WITH-CURRENT-CONTINUATION LAMBDA LET IF BEGIN))))

   This next 'while-example' structure defines an example procedure
'foo' that uses 'while'.  Since 'while-example' has no macro
definitions, there is no need for any 'for-syntax' clauses; it imports
'while' from the 'while-loops' structure only at the ground storey,
because it has no macro bindings to evaluate the transformer expressions
of:

     (define-structure while-example (export foo)
       (open scheme while-loops)
       (begin
         (define (foo x)
           (while (> x 9)
             (if (integer? (sqrt x))
                 (exit (expt x 2))
                 (set! x (- x 1)))))))

   ---------- Footnotes ----------

   (1) While such facilities are not built-in to Scheme48, there is a
package to do this, which will probably be integrated at some point soon
into Scheme48.

   (2) This would be more accurately named 'syntactic tower,' as it has
nothing to do with reflection.

   (3) This is actually only in the default config package of the
default development environment.  The full mechanism is very general.


File: scheme48.info,  Node: Static type system,  Prev: Macros in concert with modules,  Up: Module system

3.4 Static type system
======================

Scheme48 supports a rudimentary static type system.  It is intended
mainly to catch some classes of type and arity mismatch errors early, at
compile-time.  By default, there is only _extremely_ basic analysis,
which is typically only good enough to catch arity errors and the really
egregious type errors.  The full reconstructor, which is still not very
sophisticated, is enabled by specifying an optimizer pass that invokes
the code usage analyzer.  The only optimizer pass built-in to Scheme48,
the automatic procedure integrator, named 'auto-integrate', does so.

   The type reconstructor attempts to assign the most specific type it
can to program terms, signalling warnings for terms that are certain to
be invalid by Scheme's dynamic semantics.  Since the reconstructor is
not very sophisticated, it frequently gives up and assigns very general
types to many terms.  Note, however, that it is very lenient in that it
only assigns more general types: it will _never_ signal a warning
because it could not reconstruct a very specific type.  For example, the
following program will produce no warnings:

     (define (foo x y) (if x (+ y 1) (car y)))

Calls to 'foo' that are clearly invalid, such as '(foo #t 'a)', could
cause the type analyzer to signal warnings, but it is not sophisticated
enough to determine that 'foo''s second argument must be either a number
or a pair; it simply assigns a general value type (see below).

   There are some tricky cases that depend on the order by which
arguments are evaluated in a combination, because that order is not
specified in Scheme.  In these cases, the relevant types are narrowed to
the most specific ones that could not possibly cause errors at run-time
for any order.  For example,

     (lambda (x) (+ (begin (set! x '(3)) 5) (car x)))

will be assigned the type '(proc (:pair) :number)', because, if the
arguments are evaluated right-to-left, and 'x' is not a pair, there will
be a run-time type error.

   The type reconstructor presumes that all code is potentially
reachable, so it may signal warnings for code that the most trivial
control flow analyzer could decide unreachable.  For example, it would
signal a warning for '(if #t 3 (car 7))'.  Furthermore, it does not
account for continuation throws; for example, though it is a perfectly
valid Scheme program, the type analyzer might signal a warning for this
code:

     (call-with-current-continuation
       (lambda (k) (0 (k))))

   The type system is based on a type lattice.  There are several
maximum or 'top' elements, such as ':values', ':syntax', and
':structure'; and one minimum or 'bottom' element, ':error'.  This
description of the type system makes use of the following notations: 'E
: T' means that the term E has the type, or some compatible subtype of,
T; and 'T--_{A} <= T--_{B}' means that T-_{A} is a compatible subtype of
T-_{B} -- that is, any term whose static type is T-_{A} is valid in any
context that expects the type T-_{B} --.

   Note that the previous text has used the word 'term,' not
'expression,' because static types are assigned to not only Scheme
expressions.  For example, 'cond' macro has the type ':syntax'.
Structures in the configuration language also have static types: their
interfaces.  (Actually, they really have the type ':structure', but this
is a deficiency in the current implementation's design.)  Types, in
fact, have their own type: ':type'.  Here are some examples of values,
first-class or otherwise, and their types:

     cond : :syntax

     (values 1 'foo '(x . y))
       : (some-values :exact-integer :symbol :pair)

     :syntax : :type

     3 : :exact-integer

     (define-structure foo (export a b) ...)
     foo : (export a b)

   One notable deficiency of the type system is the absence of any sort
of parametric polymorphism.

 -- type constructor: join type ...
 -- type constructor: meet type ...
     'Join' and 'meet' construct the supremum and infimum elements in
     the type lattice of the given types.  That is, for any two disjoint
     types T-_{A} and T-_{B}, let T-_{J} be '(join T--_{A} T--_{B})' and
     T-_{M} be '(meet T--_{A} T--_{B})':

        * T-_{J} <= T-_{A} and T-_{J} <= T-_{B}
        * T-_{A} <= T-_{M} and T-_{B} <= T-_{M}

     For example, '(join :pair :null)' allows either pairs or nil, i.e.
     lists, and '(meet :integer :exact)' accepts only integers that are
     also exact.

     (More complete definitions of supremum, infimum, and other elements
     of lattice theory, may be found elsewhere.)

 -- type: :error
     This is the minimal, or 'bottom,' element in the type lattice.  It
     is the type of, for example, calls to 'error'.

 -- type: :values
 -- type: :arguments
     All Scheme _expressions_ have the type ':values'.  They may have
     more specific types as well, but all expressions' types are
     compatible subtypes of ':values'.  ':Values' is a maximal element
     of the type lattice.  ':Arguments' is synonymous with ':values'.

 -- type: :value
     Scheme expressions that have a single result have the type
     ':value', or some compatible subtype thereof; it is itself a
     compatible subtype of ':values'.

 -- type constructor: some-values type ...
     'Some-values' is used to denote the types of expressions that have
     multiple results: if 'E_{1} ... E_{N}' have the types 'T_{1} ...
     T_{N}', then the Scheme expression '(values E_{1} ... E_{N})' has
     the type '(some-values T_{1} ... T_{N})'.

     'Some-values'-constructed types are compatible subtypes of
     ':values'.

     'Some-values' also accepts 'optional' and 'rest' types, similarly
     to Common Lisp's 'optional' and 'rest' formal parameters.  The
     sequence of types may contain a '&opt' token, followed by which is
     any number of further types, which are considered to be optional.
     For example, 'make-vector''s domain is '(some-values :exact-integer
     &opt :value)'.  There may also be a '&rest' token, which must
     follow the '&opt' token if there is one.  Following the '&rest'
     token is one more type, which the rest of the sequents in a
     sequence after the required or optional sequents must satisfy.  For
     example, 'map''s domain is '(some-values :procedure (join :pair
     :null) &rest (join :pair :null))': it accepts one procedure and at
     least one list (pair or null) argument.

 -- type constructor: procedure domain codomain
 -- type constructor: proc (arg-type ...) result-type
     Procedure type constructors.  Procedure types are always compatible
     subtypes of ':value'.  'Procedure' is a simple constructor from a
     specific domain and codomain; DOMAIN and CODOMAIN must be
     compatible subtypes of ':values'.  'Proc' is a more convenient
     constructor.  It is equivalent to '(procedure (some-values ARG-TYPE
     ...) RESULT-TYPE)'.

 -- type: :boolean
 -- type: :char
 -- type: :null
 -- type: :unspecific
 -- type: :pair
 -- type: :string
 -- type: :symbol
 -- type: :vector
 -- type: :procedure
 -- type: :input-port
 -- type: :output-port
     Types that represent standard Scheme data.  These are all
     compatible subtypes of ':value'.  ':Procedure' is the general type
     for all procedures; see 'proc' and 'procedure' for procedure types
     with specific domains and codomains.

 -- type: :number
 -- type: :complex
 -- type: :real
 -- type: :rational
 -- type: :integer
     Types of the Scheme numeric tower.  ':integer <= :rational <= :real
     <= :complex <= :number'

 -- type: :exact
 -- type: :inexact
 -- type: :exact-integer
 -- type: :inexact-real
     ':Exact' and ':inexact' are the types of exact and inexact numbers,
     respectively.  They are typically met with one of the types in the
     numeric tower above; ':exact-integer' and ':inexact-real' are two
     conveniences for the most common meets.

 -- type: :other
     ':Other' is for types that do not fall into any of the previous
     value categories.  (':other <= :value') All new types introduced,
     for example by 'loophole' (*note Type annotations::), are
     compatible subtypes of ':other'.

 -- type constructor: variable type
     This is the type of all assignable variables, where 'TYPE <=
     :value'.  Assignment to variables whose types are value types, not
     assignable variable types, is invalid.

 -- type: :syntax
 -- type: :structure
     ':Syntax' and ':structure' are two other maximal elements of the
     type lattice, along with ':values'.  ':Syntax' is the type of
     macros or syntax transformers.  ':Structure' is the general type of
     all structures.

3.4.1 Types in the configuration language
-----------------------------------------

Scheme48's configuration language has several places in which to write
types.  However, due to the definitions of certain elements of the
configuration language, notably the 'export' syntax, the allowable type
syntax is far more limited than the above.  Only the following are
provided:

 -- type: :values
 -- type: :value
 -- type: :arguments
 -- type: :syntax
 -- type: :structure
     All of the built-in maximal elements of the type lattice are
     provided, as well as the simple compatible subtype ':values',
     ':value'.

 -- type: :boolean
 -- type: :char
 -- type: :null
 -- type: :unspecific
 -- type: :pair
 -- type: :string
 -- type: :symbol
 -- type: :vector
 -- type: :procedure
 -- type: :input-port
 -- type: :output-port
 -- type: :number
 -- type: :complex
 -- type: :real
 -- type: :rational
 -- type: :integer
 -- type: :exact-integer
     These are the only value types provided in the configuration
     language.  Note the conspicuous absence of ':exact', ':inexact',
     and ':inexact-real'.

 -- type constructor: procedure domain codomain
 -- type constructor: proc (arg-type ...) result-type
     These two are the only type constructors available.  Note here the
     conspicuous absence of 'some-values', so procedure types that are
     constructed by 'procedure' can accept only one argument (or use the
     overly general ':values' type) & return only one result (or, again,
     use ':values' for the codomain), and procedure types that are
     constructed by 'proc' are similar in the result type.


File: scheme48.info,  Node: System facilities,  Next: Multithreading,  Prev: Module system,  Up: Top

4 System facilities
*******************

This chapter details many facilities that the Scheme48 run-time system
provides.

* Menu:

* System features::
* Condition system::
* Bitwise manipulation::
* Generic dispatch system::
* I/O system::
* Reader & writer::
* Records::
* Suspending and resuming heap images::


File: scheme48.info,  Node: System features,  Next: Condition system,  Up: System facilities

4.1 System features
===================

Scheme48 provides a variety of miscellaneous features built-in to the
system.

* Menu:


* Miscellaneous features::
* Various utilities::
* Filenames::
* Fluid/dynamic bindings::
* ASCII character encoding::
* Integer enumerations::
* Cells::
* Queues::
* Hash tables::
* Weak references::
* Type annotations::
* Explicit renaming macros::


File: scheme48.info,  Node: Miscellaneous features,  Next: Various utilities,  Up: System features

4.1.1 Miscellaneous features
----------------------------

The structure 'features' provides some very miscellaneous features in
Scheme48.

 -- procedure: immutable? object --> boolean
 -- procedure: make-immutable! object --> object
     All Scheme objects in Scheme48 have a flag determining whether or
     not they may be mutated.  All immediate Scheme objects ('()', '#f',
     &c.) are immutable; all fixnums (small integers) are immutable; and
     all stored objects -- vectors, pairs, &c. -- may be mutable.
     'Immutable?' returns '#t' if OBJECT may not be mutated, and
     'make-immutable!', a bit ironically, modifies OBJECT so that it may
     not be mutated, if it was not already immutable, and returns it.

          (immutable? #t)                         => #t
          (define p (cons 1 2))
          (immutable? p)                          => #f
          (car p)                                 => 1
          (set-car! p 5)
          (car p)                                 => 5
          (define q (make-immutable! p))
          (eq? p q)                               => #t
          (car p)                                 => 5
          (immutable? q)                          => #t
          (set-car! p 6)                          error-> immutable pair

 -- procedure: string-hash string --> integer-hash-code
     Computes a basic but fast hash of STRING.

          (string-hash "Hello, world!")           => 1161

 -- procedure: force-output port --> unspecified
     Forces all buffered output to be sent out of PORT.

     This is identical to the binding of the same name exported by the
     'i/o' structure (*note Ports::).

 -- procedure: current-noise-port --> output-port
     The current noise port is a port for sending noise messages that
     are inessential to the operation of a program.

   The 'silly' structure exports a single procedure, implemented as a VM
primitive for the silly reason of efficiency, hence the name of the
structure.(1)  It is used in an inner loop of the reader.

 -- procedure: reverse-list->string char-list count --> string
     Returns a string of the first COUNT characters in CHAR-LIST, in
     reverse.  It is a serious error if CHAR-LIST is not a list whose
     length is at least COUNT; the error is not detected by the VM, so
     bogus pointers may be involved as a result.  Use this routine with
     care in inner loops.

   The 'debug-messages' structure exports a procedure for emitting very
basic debugging messages for low-level problems.

 -- procedure: debug-message item ... --> unspecified
     Prints ITEM ... directly to an error port,(2) eliding buffering and
     thread synchronization on the Scheme side.  Objects are printed as
     follows:

        * Fixnums (small integers) are written in decimal.

        * Characters are written literally with a '#\' prefix.  No
          naming translation is performed, so the space and newline
          characters are written literally, not as '#\space' or
          '#\newline'.

        * Records are written as #{TYPE-NAME}, where TYPE-NAME is the
          name of the record's type.

        * Strings and symbols are written literally.

        * Booleans and the empty list are written normally, i.e. as
          '#t', '#f', or '()'.

        * Pairs are written as '(...)'.

        * Vectors are written as '#(...)'.

        * Objects of certain primitive types are written as #{TYPE}:
          procedures, templates, locations, code (byte) vectors, and
          continuations.(3)

        * Everything else is printed as #{???}.

   The 'code-quote' structure exports a variant of 'quote' that is
useful in some sophisticated macros.

 -- special form: code-quote object --> object
     Evaluates to the literal value of OBJECT.  This is semantically
     identical to 'quote', but OBJECT may be anything, and the compiler
     will not signal any warnings regarding its value, while such
     warnings would be signalled for 'quote' expressions that do not
     wrap readable S-expressions: arbitrary, compound, unreadable data
     may be stored in 'code-quote'.  Values computed at compile-time may
     thus be transmitted to run-time code.  However, care should be
     taken in doing this.

   ---------- Footnotes ----------

   (1) The author of this manual is not at fault for this nomenclature.

   (2) On Unix, this is 'stderr', the standard I/O error output file.

   (3) Continuations here are in the sense of VM stack frames, not
escape procedures as obtained using 'call-with-current-continuation'.


File: scheme48.info,  Node: Various utilities,  Next: Filenames,  Prev: Miscellaneous features,  Up: System features

4.1.2 Various utilities
-----------------------

The 'util' structure contains some miscellaneous utility routines
extensively used internally in the run-time system.  While they are not
meant to compose a comprehensive library (such as, for example, [SRFI
1]), they were found useful in building the run-time system without
introducing massive libraries into the core of the system.

 -- procedure: unspecific --> unspecific
     Returns Scheme48's "unspecific" token, which is used wherever R5RS
     uses the term 'unspecific' or 'unspecified.'  In this manual, the
     term 'unspecified' is used to mean that the values returned by a
     particular procedure are not specified and may be anything,
     including a varying number of values, whereas 'unspecific' refers
     to Scheme48's specific 'unspecific' value that the 'unspecific'
     procedure returns.

 -- procedure: reduce kons knil list --> final-knil
     Reduces LIST by repeatedly applying KONS to elements of LIST and
     the current KNIL value.  This is the fundamental list recursion
     operator.

          (reduce KONS KNIL
                  (cons ELT_{1}
                        (cons ELT_{2}
                              (...(cons ELT_{N} '())...))))
              ==
          (KONS ELT_{1}
                (KONS ELT_{2}
                      (...(KONS ELT_{N} KNIL)...)))

     Example:

          (reduce append '() '((1 2 3) (4 5 6) (7 8 9)))
              => (1 2 3 4 5 6 7 8 9)
          (append '(1 2 3)
                  (append '(4 5 6)
                          (append '(7 8 9) '())))
              => (1 2 3 4 5 6 7 8 9)

 -- procedure: fold combiner list accumulator --> final-accumulator
     Folds LIST into an accumulator by repeatedly combining each element
     into an accumulator with COMBINER.  This is the fundamental list
     iteration operator.

          (fold COMBINER
                (list ELT_{1} ELT_{2} ... ELT_{N})
                ACCUMULATOR)
              ==
          (let* ((accum_{1} (COMBINER ELT_{1} ACCUMULATOR))
                 (accum_{2} (COMBINER ELT_{2} accum_{1}))
                 ...
                 (accum_{N} (COMBINER ELT_{N} accum_{N-1})))
            accum_{N})

     Example:

          (fold cons '() '(a b c d))
              => (d c b a)
          (cons 'd (cons 'c (cons 'b (cons 'a '()))))
              => (d c b a)

 -- procedure: fold->2 combiner list accumulator_{1} accumulator_{2} -->
          [final-accumulator_{1} final-accumulator_{2}]
 -- procedure: fold->3 combiner list accumulator_{1} accumulator_{2}
          accumulator_{3} --> [final-accumulator_{1}
          final-accumulator_{2} final-accumulator_{3}]
     Variants of 'fold' for two and three accumulators, respectively.

          ;;; Partition LIST by elements that satisfy PRED? and those
          ;;; that do not.

          (fold->2 (lambda (elt satisfied unsatisfied)
                     (if (PRED? elt)
                         (values (cons elt satisfied) unsatisfied)
                         (values satisfied (cons elt unsatisfied))))
                   LIST
                   '() '())

 -- procedure: filter predicate list --> filtered-list
     Returns a list of all elements in LIST that satisfy PREDICATE.

          (filter odd? '(3 1 4 1 5 9 2 6 5 3 5))
              => (3 1 1 5 9 5 3 5)

 -- procedure: posq object list --> integer or '#f'
 -- procedure: posv object list --> integer or '#f'
 -- procedure: position object list --> integer or '#f'
     These find the position of the first element equal to OBJECT in
     LIST.  'Posq' compares elements by 'eq?'; 'posv' compares by
     'eqv?'; 'position' compares by 'equal?'.

          (posq 'c '(a b c d e f))
              => 2
          (posv 1/2 '(1 1/2 2 3/2))
              => 1
          (position '(d . e) '((a . b) (b . c) (c . d) (d . e) (e . f)))
              => 3

 -- procedure: any predicate list --> value or '#f'
 -- procedure: every predicate list --> boolean
     'Any' returns the value that PREDICATE returns for the first
     element in LIST for which PREDICATE returns a true value; if no
     element of LIST satisfied PREDICATE, 'any' returns '#f'.  'Every'
     returns '#t' if every element of LIST satisfies PREDICATE, or '#f'
     if there exist any that do not.

          (any (lambda (x) (and (even? x) (sqrt x)))
               '(0 1 4 9 16))
              => 2
          (every odd? '(1 3 5 7 9))
              => #t

 -- procedure: sublist list start end --> list
     Returns a list of the elements in LIST including & after that at
     the index START and before the index END.

          (sublist '(a b c d e f g h i) 3 6)      => (d e f)

 -- procedure: last list --> value
     Returns the last element in LIST.  'Last''s effect is undefined if
     LIST is empty.

          (last '(a b c))                         => c

 -- procedure: insert object list elt< --> list
     Inserts OBJECT into the sorted list LIST, comparing the order of
     OBJECT and each element by ELT<.

          (insert 3 '(0 1 2 4 5) <)               => (0 1 2 3 4 5)


File: scheme48.info,  Node: Filenames,  Next: Fluid/dynamic bindings,  Prev: Various utilities,  Up: System features

4.1.3 Filenames
---------------

There are some basic filename manipulation facilities exported by the
'filenames' structure.(1)

 -- constant: *scheme-file-type* --> symbol
 -- constant: *load-file-type* --> symbol
     '*Scheme-file-type*' is a symbol denoting the file extension that
     Scheme48 assumes for Scheme source files; any other extension, for
     instance in the filename list of a structure definition, must be
     written explicitly.  '*Load-file-type*' is a symbol denoting the
     preferable file extension to load files from.  ('*Load-file-type*'
     was used mostly in bootstrapping Scheme48 from Pseudoscheme or T
     long ago and is no longer very useful.)

 -- procedure: file-name-directory filename --> string
 -- procedure: file-name-nondirectory filename --> string
     'File-name-directory' returns the directory component of the
     filename denoted by the string FILENAME, including a trailing
     separator (on Unix, '/').  'File-name-nondirectory' returns
     everything but the directory component of the filename denoted by
     the string FILENAME, including the extension.

          (file-name-directory "/usr/local/lib/scheme48/scheme48.image")
              => "/usr/local/lib/scheme48/"
          (file-name-nondirectory "/usr/local/lib/scheme48/scheme48.image")
              => "scheme48.image"
          (file-name-directory "scheme48.image")
              => ""
          (file-name-nondirectory "scheme48.image")
              => "scheme48.image"

   "Namelists" are platform-independent means by which to name files.
They are represented as readable S-expressions of any of the following
forms:

'BASENAME'
     represents a filename with only a basename and no directory or file
     type/extension;

'(DIRECTORY BASENAME [TYPE])'
     represents a filename with a single preceding directory component
     and an optional file type/extension; and

'((DIRECTORY ...) BASENAME [TYPE])'
     represents a filename with a sequence of directory components, a
     basename, and an optional file type/extension.

   Each atomic component -- that is, the basename, the type/extension,
and each individual directory component -- may be either a string or a
symbol.  Symbols are converted to the canonical case of the host
operating system by 'namestring' (on Unix, lowercase); the case of
string components is not touched.

 -- procedure: namestring namelist directory default-type --> string
     Converts NAMELIST to a string in the format required by the host
     operating system.(2)  If NAMELIST did not have a directory
     component, DIRECTORY, a string in the underlying operating system's
     format for directory prefixes, is added to the resulting
     namestring; and, if NAMELIST did not have a type/extension,
     DEFAULT-TYPE, which may be a string or a symbol and which should
     _not_ already contain the host operating system's delimiter
     (usually a dot), is appended to the resulting namestring.

     DIRECTORY or DEFAULT-TYPE may be '#f', in which case they are not
     prefixed or appended to the resulting filename.

          (namestring 'foo #f #f)                 => "foo"
          (namestring 'foo "bar" 'baz)            => "bar/foo.baz"
          (namestring '(rts defenum) "scheme" 'scm)
              => "scheme/rts/defenum.scm"
          (namestring '((foo bar) baz quux) "zot" #f)
              => "zot/foo/bar/baz.quux"
          (namestring "zot/foo/bar/baz.quux" #f "mumble")
              => "zot/foo/bar/baz.quux.mumble"

4.1.3.1 Filename translations
.............................

Scheme48 keeps a registry of "filename translations", translations from
filename prefixes to the real prefixes.  This allows abstraction of
actual directory prefixes without necessitating running Scheme code to
construct directory pathnames (for example, in configuration files).
Interactively, in the usual command processor, users can set filename
translations with the ',translate'; *note Basic commands::.

 -- procedure: translations --> string/string-alist
     Returns the alist of filename translations.

 -- procedure: set-translation! from to --> unspecified
     Adds a filename prefix translation, overwriting an existing one if
     one already existed.

 -- procedure: translate filename --> translated-filename
     Translates the first prefix of FILENAME found in the registry of
     translations and returns the translated filename.

     (set-translation! "s48" "/home/me/scheme/scheme48/scheme")
     (translate (namestring '(bcomp frame) "s48" 'scm))
         => "/home/me/scheme/scheme48/scheme/bcomp/frame.scm"
     (translate (namestring "comp-packages" "s48" 'scm))
         => "/home/me/scheme/scheme48/scheme/comp-packages.scm"
     (translate "s48/frobozz")
         => "/home/me/scheme/scheme48/scheme/frobozz"
     (set-translation! "scheme48" "s48")
     (translate (namestring '((scheme48 big) filename) #f 'scm))
         => scheme48/big/filename.scm
     (translate (translate (namestring '((scheme48 big) filename) #f 'scm)))
         => "/home/me/scheme/scheme48/scheme/big/filename.scm"

   One filename translation is built-in, mapping '=scheme48/' to the
directory of system files in a Scheme48 installation, which on Unix is
typically a directory in '/usr/local/lib'.

     (translate "=scheme48/scheme48.image")
         => /usr/local/scheme48/scheme48.image

   ---------- Footnotes ----------

   (1) The facilities Scheme48 provides are very rudimentary, and they
are not intended to act as a coherent and comprehensive pathname or
logical name facility such as that of Common Lisp.  However, they served
the basic needs of Scheme48's build process when they were originally
created.

   (2) However, the current standard distribution of Scheme48 is
specific to Unix: the current code implements only Unix filename
facilities.


File: scheme48.info,  Node: Fluid/dynamic bindings,  Next: ASCII character encoding,  Prev: Filenames,  Up: System features

4.1.4 Fluid/dynamic bindings
----------------------------

The 'fluids' structure provides a facility for dynamically bound
resources, like special variables in Common Lisp, but with first-class,
unforgeable objects.

   Every thread (*note Multithreading::) in Scheme48 maintains a "fluid
or dynamic environment".  It maps "fluid descriptors" to their values,
much like a lexical environment maps names to their values.  The dynamic
environment is implemented by deep binding and dynamically scoped.
Fluid variables are represented as first-class objects for which there
is a top-level value and possibly a binding in the current dynamic
environment.  Escape procedures, as created with Scheme's
'call-with-current-continuation', also store & preserve the dynamic
environment at the time of their continuation's capture and restore it
when invoked.

   The convention for naming variables that are bound to fluid objects
is to add a prefix of '$' (dollar sign); e.g., '$foo'.

 -- procedure: make-fluid top-level-value --> fluid
     Fluid constructor.

 -- procedure: fluid fl --> value
 -- procedure: set-fluid! fl value --> unspecified
 -- procedure: fluid-cell-ref fluid-cell --> value
 -- procedure: fluid-cell-set! fluid-cell value --> unspecified
     'Fluid' returns the value that the current dynamic environment
     associates with FL, if it has an association; if not, it returns
     FL's top-level value, as passed to 'make-fluid' to create FL.
     'Set-fluid!' assigns the value of the association in the current
     dynamic environment for FL to VALUE, or, if there is no such
     association, it assigns the top-level value of FL to VALUE.  Direct
     assignment of fluids is deprecated, however, and may be removed in
     a later release; instead, programmers should use fluids that are
     bound to mutable cells (*note Cells::).  'Fluid-cell-ref' and
     'fluid-cell-set!' are conveniences for this; they simply call the
     corresponding cell operations after fetching the cell that the
     fluid refers to by using 'fluid'.

 -- procedure: let-fluid fluid value thunk --> values
 -- procedure: let-fluids fluid_{0} value_{0} fluid_{1} value_{1} ...
          thunk --> values
     These dynamically bind their fluid arguments to the corresponding
     value arguments and apply THUNK with the new dynamic environment,
     restoring the old one after THUNK returns and returning the value
     it returns.

     (define $mumble (make-fluid 0))

     (let ((a (fluid $mumble))
           (b (let-fluid $mumble 1
                (lambda () (fluid $mumble))))
           (c (fluid $mumble))
           (d (let-fluid $mumble 2
                (lambda ()
                  (let-fluid $mumble 3
                    (lambda () (fluid $mumble)))))))
       (list a b c d))
         => (0 1 0 3)

     (let ((note (lambda (when)
                   (display when)
                   (display ": ")
                   (write (fluid $mumble))
                   (newline))))
       (note 'initial)
       (let-fluid $mumble 1 (lambda () (note 'let-fluid)))
       (note 'after-let-fluid)
       (let-fluid $mumble 1
         (lambda ()
           (note 'outer-let-fluid)
           (let-fluid $mumble 2 (lambda () (note 'inner-let-fluid)))))
       (note 'after-inner-let-fluid)
       ((call-with-current-continuation
          (lambda (k)
            (lambda ()
              (let-fluid $mumble 1
                (lambda ()
                  (note 'let-fluid-within-cont)
                  (let-fluid $mumble 2
                    (lambda () (note 'inner-let-fluid-within-cont)))
                  (k (lambda () (note 'let-fluid-thrown)))))))))
       (note 'after-throw))
         -| initial: 0
         -| let-fluid: 1
         -| after-let-fluid: 0
         -| outer-let-fluid: 1
         -| inner-let-fluid: 2
         -| let-fluid-within-cont: 1
         -| inner-let-fluid-within-cont: 2
         -| let-fluid-thrown: 0
         -| after-throw: 0


File: scheme48.info,  Node: ASCII character encoding,  Next: Integer enumerations,  Prev: Fluid/dynamic bindings,  Up: System features

4.1.5 ASCII character encoding
------------------------------

These names are exported by the 'ascii' structure.

 -- procedure: char->ascii char --> ascii-integer
 -- procedure: ascii->char ascii-integer --> character
     These convert characters to and from their integer ASCII encodings.
     'Char->ascii' and 'ascii->char' are similar to R5RS's
     'char->integer' and 'integer->char', but they are guaranteed to use
     the ASCII encoding.  Scheme48's 'integer->char' and 'char->integer'
     deliberately do not use the ASCII encoding to encourage programmers
     to make use of only what R5RS guarantees.

          (char->ascii #\a)                       => 97
          (ascii->char 97)                        => #\a

 -- constant: ascii-limit --> integer
 -- constant: ascii-whitespaces --> ascii-integer-list
     'Ascii-limit' is an integer that is one greater than the highest
     number that 'char->ascii' may return or 'ascii->char' will accept.
     'Ascii-whitespaces' is a list of the integer encodings of all
     characters that are considered whitespace: space (32), horizontal
     tab (9), line-feed/newline (10), vertical tab (11), form-feed/page
     (12), and carriage return (13).


File: scheme48.info,  Node: Integer enumerations,  Next: Cells,  Prev: ASCII character encoding,  Up: System features

4.1.6 Integer enumerations
--------------------------

Scheme48 provides a facility for "integer enumerations", somewhat akin
to C enums.  The names described in this section are exported by the
'enumerated' structure.

   *Note:* These enumerations are _not_ compatible with the
enumerated/finite type facility (*note Enumerated/finite types and
sets::).

 -- syntax: define-enumeration enumeration-name (enumerand-name ...)
     Defines ENUMERATION-NAME to be a static enumeration.  (Note that it
     is _not_ a regular variable.  It is actually a macro, though its
     exact syntax is not exposed; it must be exported with the ':syntax'
     type (*note Static type system::).)  ENUMERATION-NAME thereafter
     may be used with the enumeration operators described below.

 -- syntax: enum enumeration-name enumerand-name --> enumerand-integer
 -- syntax: components enumeration-name --> component-vector
     'Enum' expands to the integer value represented symbolically by
     ENUMERAND-NAME in the enumeration ENUMERATION-NAME as defined by
     'define-enumeration'.  'Components' expands to a literal vector of
     the components in ENUMERATION-NAME as defined by
     'define-enumeration'.  In both cases, ENUMERAND-NAME must be
     written literally as the name of the enumerand; see
     'name->enumerand' for extracting an enumerand's integer given a
     run-time symbol naming an enumerand.

 -- syntax: enumerand->name enumerand-integer enumeration-name -->
          symbol
 -- syntax: name->enumerand enumerand-name enumeration-name -->
          integer-enumerand
     'Enumerand->name' expands to a form that evaluates to the symbolic
     name that the integer value of the expression ENUMERAND-INTEGER is
     mapped to by ENUMERATION-NAME as defined by 'define-enumeration'.
     'Name->enumerand' expands to a form that evaluates to the integer
     value of the enumerand in ENUMERATION-NAME that is represented
     symbolically by the value of the expression ENUMERAND-NAME.

   The 'enum-case' structure provides a handy utility of the same name
for dispatching on enumerands.

 -- syntax: enum-case
          (enum-case ENUMERATION-NAME KEY
            ((ENUMERAND-NAME ...) BODY)
            ...
            [(else ELSE-BODY)])
     Matches KEY with the clause one of whose names maps in
     ENUMERATION-NAME to the integer value of KEY.  KEY must be an
     exact, non-negative integer.  If no matching clause is found, and
     ELSE-BODY is present, 'enum-case' will evaluate ELSE-BODY; if
     ELSE-BODY is not present, 'enum-case' will return an unspecific
     value.

   Examples:

     (define-enumeration foo
       (bar
        baz))

     (enum foo bar)                          => 0
     (enum foo baz)                          => 1

     (enum-case foo (enum foo bar)
       ((baz) 'x)
       (else  'y))
         => y

     (enum-case foo (enum foo baz)
       ((bar) 'a)
       ((baz) 'b))
         => b

     (enumerand->name 1 foo)                 => baz
     (name->enumerand 'bar foo)              => 0
     (components foo)                        => #(bar baz)


File: scheme48.info,  Node: Cells,  Next: Queues,  Prev: Integer enumerations,  Up: System features

4.1.7 Cells
-----------

Scheme48 also provides a simple mutable cell data type from the 'cells'
structure.  It uses them internally for local, lexical variables that
are assigned, but cells are available still to the rest of the system
for general use.

 -- procedure: make-cell contents --> cell
 -- procedure: cell? object --> boolean
 -- procedure: cell-ref cell --> value
 -- procedure: cell-set! cell value --> unspecified
     'Make-cell' creates a new cell with the given contents.  'Cell?' is
     the disjoint type predicate for cells.  'Cell-ref' returns the
     current contents of CELL.  'Cell-set!' assigns the contents of CELL
     to VALUE.

   Examples:

     (define cell (make-cell 42))
     (cell-ref cell)                         => 42
     (cell? cell)                            => #t
     (cell-set! cell 'frobozz)
     (cell-ref cell)                         => frobozz


File: scheme48.info,  Node: Queues,  Next: Hash tables,  Prev: Cells,  Up: System features

4.1.8 Queues
------------

The 'queues' structure exports names for procedures that operate on
simple first-in, first-out queues.

 -- procedure: make-queue --> queue
 -- procedure: queue? object --> boolean
     'Make-queue' constructs an empty queue.  'Queue?' is the disjoint
     type predicate for queues.

 -- procedure: queue-empty? queue --> boolean
 -- procedure: empty-queue! queue --> unspecified
     'Queue-empty?' returns '#t' if QUEUE contains zero elements or '#f'
     if it contains some.  'Empty-queue!' removes all elements from
     QUEUE.

 -- procedure: enqueue! queue object --> unspecified
 -- procedure: dequeue! queue --> value
 -- procedure: maybe-dequeue! queue --> value or '#f'
 -- procedure: queue-head queue --> value
     'Enqueue!' adds OBJECT to QUEUE.  'Dequeue!' removes & returns the
     next object available from QUEUE; if QUEUE is empty, 'dequeue!'
     signals an error.  'Maybe-dequeue!' is like 'dequeue!', but it
     returns '#f' in the case of an absence of any element, rather than
     signalling an error.  'Queue-head' returns the next element
     available from QUEUE without removing it, or it signals an error if
     QUEUE is empty.

 -- procedure: queue-length queue --> integer
     Returns the number of objects in QUEUE.

 -- procedure: on-queue? queue object --> boolean
 -- procedure: delete-from-queue! queue object --> unspecified
     'On-queue?' returns true if QUEUE contains OBJECT or '#f' if not.
     'Delete-from-queue!' removes the first occurrence of OBJECT from
     QUEUE that would be dequeued.

 -- procedure: queue->list queue --> list
 -- procedure: list->queue list --> queue
     These convert queues to and from lists of their elements.
     'Queue->list' returns a list in the order in which its elements
     were added to the queue.  'List->queue' returns a queue that will
     produce elements starting at the head of the list.

   Examples:

     (define q (make-queue))
     (enqueue! q 'foo)
     (enqueue! q 'bar)
     (queue->list q)                         => (foo bar)
     (on-queue? q 'bar)                      => #t
     (dequeue! q)                            => 'foo
     (queue-empty? q)                        => #f
     (delete-from-queue! queue 'bar)
     (queue-empty? q)                        => #t
     (enqueue! q 'frobozz)
     (empty-queue! q)
     (queue-empty? q)                        => #t
     (dequeue! q)                            error-> empty queue

   Queues are integrated with Scheme48's optimistic concurrency (*note
Optimistic concurrency::) facilities, in that every procedure exported
except for 'queue->list' ensures fusible atomicity in operation -- that
is, every operation except for 'queue->list' ensures that the
transaction it performs is atomic, and that it may be fused within
larger atomic transactions, as transactions wrapped within
'call-ensuring-atomicity' &c. may be.


File: scheme48.info,  Node: Hash tables,  Next: Weak references,  Prev: Queues,  Up: System features

4.1.9 Hash tables
-----------------

Scheme48 provides a simple hash table facility in the structure
'tables'.

 -- procedure: make-table [hasher] --> table
 -- procedure: make-string-table --> string-table
 -- procedure: make-symbol-table --> symbol-table
 -- procedure: make-integer-table --> integer-table
     Hash table constructors.  'Make-table' creates a table that hashes
     keys either with HASHER, if it is passed to 'make-table', or
     'default-hash-function', and it compares keys for equality with
     'eq?', unless they are numbers, in which case it compares with
     'eqv?'.  'Make-string-table' makes a table whose hash function is
     'string-hash' and that compares the equality of keys with
     'string=?'.  'Make-symbol-table' constructs a table that hashes
     symbol keys by converting them to strings and hashing them with
     'string-hash'; it compares keys' equality by 'eq?'.  Tables made by
     'make-integer-table' hash keys by taking their absolute value, and
     test for key equality with the '=' procedure.

 -- procedure: make-table-maker comparator hasher --> table-maker
     Customized table constructor constructor: this returns a nullary
     procedure that creates a new table that uses COMPARATOR to compare
     keys for equality and HASHER to hash keys.

 -- procedure: table? object --> boolean
     Hash table disjoint type predicate.

 -- procedure: table-ref table key --> value or '#f'
 -- procedure: table-set! table key value --> unspecified
     'Table-ref' returns the value associated with KEY in TABLE, or '#f'
     if there is no such association.  If VALUE is '#f', 'table-set!'
     ensures that there is no longer an association with KEY in TABLE;
     if VALUE is any other value, 'table-set!' creates a new association
     or assigns an existing one in TABLE whose key is KEY and whose
     associated value is VALUE.

 -- procedure: table-walk proc table --> unspecified
     'Table-walk' applies PROC to the key & value, in that order of
     arguments, of every association in TABLE.

 -- procedure: make-table-immutable! table --> table
     This makes the structure of TABLE immutable, though not its
     contents.  'Table-set!' may not be used with tables that have been
     made immutable.

 -- procedure: default-hash-function value --> integer-hash-code
 -- procedure: string-hash string --> integer-hash-code
     Two built-in hashing functions.  'Default-hash-function' can hash
     any Scheme value that could usefully be used in a 'case' clause.
     'String-hash' is likely to be fast, as it is implemented as a VM
     primitive.  'String-hash' is the same as what the 'features'
     structure exports under the same name.


File: scheme48.info,  Node: Weak references,  Next: Type annotations,  Prev: Hash tables,  Up: System features

4.1.10 Weak references
----------------------

Scheme48 provides an interface to weakly held references in basic weak
pointers and "populations", or sets whose elements are weakly held.  The
facility is in the structure 'weak'.

4.1.10.1 Weak pointers
......................

 -- procedure: make-weak-pointer contents --> weak-pointer
 -- procedure: weak-pointer? object --> boolean
 -- procedure: weak-pointer-ref weak-pointer --> value or '#f'
     'Make-weak-pointer' creates a weak pointer that points to CONTENTS.
     'Weak-pointer?' is the weak pointer disjoint type predicate.
     'Weak-pointer-ref' accesses the value contained within
     'weak-pointer', or returns '#f' if there were no strong references
     to the contents and a garbage collection occurred.  Weak pointers
     resemble cells (*note Cells::), except that they are immutable and
     hold their contents weakly, not strongly.

4.1.10.2 Populations (weak sets)
................................

 -- procedure: make-population --> population
 -- procedure: add-to-population! object population --> unspecified
 -- procedure: population->list population --> list
 -- procedure: walk-population proc population --> unspecified
     'Make-population' constructs an empty population.
     'Add-to-population!' adds OBJECT to the population POPULATION.
     'Population->list' returns a list of the elements of POPULATION.
     Note, though, that this can be dangerous in that it can create
     strong references to the population's contents and potentially leak
     space because of this.  'Walk-population' applies PROC to every
     element in POPULATION.


File: scheme48.info,  Node: Type annotations,  Next: Explicit renaming macros,  Prev: Weak references,  Up: System features

4.1.11 Type annotations
-----------------------

Scheme48 allows optional type annotations with the 'loophole' special
form from the 'loopholes' structure.

 -- syntax: loophole type expression --> values
     This is exactly equivalent in semantics to EXPRESSION, except the
     static type analyzer is informed that the whole expression has the
     type TYPE.  For details on the form of TYPE, *note Static type
     system::.

   Type annotations can be used for several different purposes:

   * simply to give more information to the static type analyzer;

   * to work as a simple abstract data type facility: passing a type
     name that does not already exist creates a new disjoint value type;
     and

   * to prevent the type system from generating warnings in the rare
     cases where it would do so incorrectly, such as in the
     'primitive-cwcc', 'primitive-catch', and 'with-continuation'
     devices (to be documented in a later edition of this manual).

   To see an example of the second use, see 'rts/jar-defrecord.scm' in
Scheme48's source tree.

   *Note:* Type annotations do _not_ damage the safety of Scheme's type
system.  They affect only the static type analyzer, which does not
change run-time object representations; it only checks type soundness of
code and generates warnings for programs that would cause run-time type
errors.


File: scheme48.info,  Node: Explicit renaming macros,  Prev: Type annotations,  Up: System features

4.1.12 Explicit renaming macros
-------------------------------

Scheme48 supports a simple low-level macro system based on explicitly
renaming identifiers to preserve hygiene.  The macro system is
well-integrated with the module system; *note Macros in concert with
modules::.

   "Explicit renaming" macro transformers operate on simple
S-expressions extended with "identifiers", which are like symbols but
contain more information about lexical context.  In order to preserve
that lexical context, transformers must explicitly call a "renamer"
procedure to produce an identifier with the proper scope.  To test
whether identifiers have the same denotation, transformers are also
given an identifier comparator.

   The facility provided by Scheme48 is almost identical to the explicit
renaming macro facility described in [Clinger 91].(1)  It differs only
by the 'transformer' keyword, which is described in the paper but not
used by Scheme48, and in the annotation of auxiliary names.

 -- syntax: define-syntax name transformer [aux-names]
     Introduces a derived syntax NAME with the given transformer, which
     may be an explicit renaming transformer procedure, a pair whose car
     is such a procedure and whose cdr is a list of auxiliary
     identifiers, or the value of a 'syntax-rules' expression.  In the
     first case, the added operand AUX-NAMES may, and usually should
     except in the case of local (non-exported) syntactic bindings, be a
     list of all of the auxiliary top-level identifiers used by the
     macro.

   Explicit renaming transformer procedures are procedures of three
arguments: an input form, an identifier renamer procedure, and an
identifier comparator procedure.  The input form is the whole form of
the macro's invocation (including, at the car, the identifier whose
denotation was the syntactic binding).  The identifier renamer accepts
an identifier as an argument and returns an identifier that is
hygienically renamed to refer absolutely to the identifier's denotation
in the environment of the macro's definition, not in the environment of
the macro's usage.  In order to preserve hygiene of syntactic
transformations, macro transformers must call this renamer procedure for
any literal identifiers in the output.  The renamer procedure is
referentially transparent; that is, two invocations of it with the same
arguments in terms of 'eq?' will produce the same results in the sense
of 'eq?'.

   For example, this simple transformer for a 'swap!' macro is
incorrect:

     (define-syntax swap!
       (lambda (form rename compare)
         (let ((a (cadr  form))
               (b (caddr form)))
           `(LET ((TEMP ,a))
              (SET! ,a ,b)
              (SET! ,b TEMP)))))

The introduction of the literal identifier 'temp' into the output may
conflict with one of the input variables if it were to also be named
'temp': '(swap! temp foo)' or '(swap! bar temp)' would produce the wrong
result.  Also, the macro would fail in another very strange way if the
user were to have a local variable named 'let' or 'set!', or it would
simply produce invalid output if there were no binding of 'let' or
'set!' in the environment in which the macro was used.  These are basic
problems of abstraction: the user of the macro should not need to know
how the macro is internally implemented, notably with a 'temp' variable
and using the 'let' and 'set!' special forms.

   Instead, the macro must hygienically rename these identifiers using
the renamer procedure it is given, and it should list the top-level
identifiers it renames (which cannot otherwise be extracted
automatically from the macro's definition):

     (define-syntax swap!
       (lambda (form rename compare)
         (let ((a (cadr  form))
               (b (caddr form)))
           `(,(rename 'LET) ((,(rename 'TEMP) ,a))
              (,(rename 'SET!) ,a ,b)
              (,(rename 'SET!) ,b ,(rename 'TEMP)))))
       (LET SET!))

   However, some macros are unhygienic by design, i.e. they insert
identifiers into the output intended to be used in the environment of
the macro's usage.  For example, consider a 'loop' macro that loops
endlessly, but binds a variable named 'exit' to an escape procedure to
the continuation of the 'loop' expression, with which the user of the
macro can escape the loop:

     (define-syntax loop
       (lambda (form rename compare)
         (let ((body (cdr form)))
           `(,(rename 'CALL-WITH-CURRENT-CONTINUATION)
              (,(rename 'LAMBDA) (EXIT)      ; Literal, unrenamed EXIT.
                (,(rename 'LET) ,(rename 'LOOP) ()
                  ,@body
                  (,(rename 'LOOP)))))))
       (CALL-WITH-CURRENT-CONTINUATION LAMBDA LET))

   Note that macros that expand to 'loop' must also be unhygienic; for
instance, this naïve definition of a 'loop-while' macro is incorrect,
because it hygienically renames 'exit' automatically by of the
definition of 'syntax-rules', so the identifier it refers to is not the
one introduced unhygienically by 'loop':

     (define-syntax loop-while
       (syntax-rules ()
         ((LOOP-WHILE test body ...)
          (LOOP (IF (NOT test)
                    (EXIT))                  ; Hygienically renamed.
                body ...))))

Instead, a transformer must be written to not hygienically rename 'exit'
in the output:

     (define-syntax loop-while
       (lambda (form rename compare)
         (let ((test (cadr form))
               (body (cddr form)))
           `(,(rename 'LOOP)
              (,(rename 'IF) (,(rename 'NOT) ,test)
                (EXIT))                      ; Not hygienically renamed.
              ,@body)))
       (LOOP IF NOT))

   To understand the necessity of annotating macros with the list of
auxiliary names they use, consider the following definition of the
'delay' form, which transforms '(delay EXP)' into '(make-promise (lambda
() EXP))', where 'make-promise' is some non-exported procedure defined
in the same module as the 'delay' macro:

     (define-syntax delay
       (lambda (form rename compare)
         (let ((exp (cadr form)))
           `(,(rename 'MAKE-PROMISE) (,(rename 'LAMBDA) () ,exp)))))

This preserves hygiene as necessary, but, while the compiler can know
whether 'make-promise' is _exported_ or not, it cannot in general
determine whether 'make-promise' is _local_, i.e. not accessible in any
way whatsoever, even in macro output, from any other modules.  In this
case, 'make-promise' is _not_ local, but the compiler cannot in general
know this, and it would be an unnecessarily heavy burden on the
compiler, the linker, and related code-processing systems to assume that
all bindings are not local.  It is therefore better(2) to annotate such
definitions with the list of auxiliary names used by the transformer:

     (define-syntax delay
       (lambda (form rename compare)
         (let ((exp (cadr form)))
           `(,(rename 'MAKE-PROMISE) (,(rename 'LAMBDA) () ,exp))))
       (MAKE-PROMISE LAMBDA))

   ---------- Footnotes ----------

   (1) For the sake of avoiding any potential copyright issues, the
paper is not duplicated here, and instead the author of this manual has
written the entirety of this section.

   (2) However, the current compiler in Scheme48 does not require this,
though the static linker does.


File: scheme48.info,  Node: Condition system,  Next: Bitwise manipulation,  Prev: System features,  Up: System facilities

4.2 Condition system
====================

As of version 1.3 (different from all older versions), Scheme48 supports
two different condition systems.  One of them, the original one, is a
simple system where conditions are represented as tagged lists.  This
section documents the original one.  The new condition system is [SRFI
34, 35], and there is a complicated translation layer between the old
one, employed by the run-time system, and the new one, which is
implemented in a layer high above that as a library, but a library which
is always loaded in the usual development environment.  See the [SRFI
34, 35] documents for documentation of the new condition system.  [SRFI
34] is available from the 'exceptions' structure; SRFI 35, from the
'conditions' structure.

   *Note:* The condition system changed in Scheme48 version 1.3.  While
the old one is still available, the names of the structures that
implement it changed.  'Signals' is now 'simple-signals', and
'conditions' is now 'simple-conditions'.  The structure that 'signals'
_now_ names implements the same interface, but with [SRFI 34, 35]
underlying it.  The structure that the name 'conditions' _now_
identifies [SRFI 35].  You will have to update all old code that relied
on the old 'signals' and 'conditions' structure either by using those
structures' new names or by invasively modifying all code to use [SRFI
34, 35].  Also, the only way to completely elide the use of the SRFIs is
to evaluate this in an environment with the 'exceptions-internal' and
'vm-exceptions' structure open:

     (begin (initialize-vm-exceptions! really-signal-condition)
            ;; INITIALIZE-VM-EXCEPTIONS! returns a very large object,
            ;; which we probably don't want printed at the REPL.
            #t)

4.2.1 Signalling, handling, and representing conditions
-------------------------------------------------------

Scheme48 provides a simple condition system.(1)  "Conditions" are
objects that describe exceptional situations.  Scheme48 keeps a registry
of "condition types", which just have references to their supertypes.
Conditions are simple objects that contain only two fields, the type and
the type-specific data (the "stuff").  Accessor procedures should be
defined for particular condition types to extract the data contained
within the 'stuff' fields of instances of of those condition types.
Condition types are represented as symbols.  "Condition handlers" are
part of the system's dynamic context; they are used to handle
exceptional situations when conditions are signalled that describe such
exceptional situations.  "Signalling" a condition signals that an
exceptional situation occurred and invokes the current condition handler
on the condition.

   Scheme48's condition system is split up into three structures:

'simple-signals'
     Exports procedures to signal conditions and construct conditions,
     as well as some utilities for common kinds of conditions.

'handle'
     Exports facilities for handling signalled conditions.

'simple-conditions'
     The system of representing conditions as objects.

   The 'simple-signals' structure exports these procedures:

 -- procedure: make-condition type-name stuff --> condition
     The condition object constructor.

 -- procedure: signal-condition condition --> values (may not return)
 -- procedure: signal type-name stuff ... --> values (may not return)
     'Signal-condition' signals the given condition.  'Signal' is a
     convenience atop the common conjunction of 'signal-condition' and
     'make-condition': it constructs a condition with the given type
     name and stuff, whereafter it signals that condition with
     'signal-condition'.

 -- procedure: error message irritant ... --> values (may not return)
 -- procedure: warn message irritant ... --> values (may not return)
 -- procedure: syntax-error message irritant ... --> expression (may not
          return)
 -- procedure: call-error message irritant ... --> values (may not
          return)
 -- procedure: note message irritant ... --> values (may not return)
     Conveniences for signalling standard condition types.  These
     procedures generally either do not return or return an unspecified
     value, unless specified to by a user of the debugger.
     'Syntax-error' returns the expression '(quote syntax-error)', if
     the condition handler returns to 'syntax-error' in the first place.

     By convention, the message should be lowercased (i.e. the first
     word should not be capitalized), and it should not end with
     punctuation.  The message is typically not a complete sentence.
     For example, these all follow Scheme48's convention:

          argument type error
          wrong number of arguments
          invalid syntax
          ill-typed right-hand side
          out of memory, unable to continue

     These, on the other hand, do not follow the convention and should
     be avoided:

          Argument type error:
          An argument of the wrong type was passed.
          possible type mismatch:
          Luser is an idiot!

     Elaboration on a message is performed usually by wrapping an
     irritant in a descriptive list.  For example, one might write:

          (error "invalid argument"
                 '(not a pair)
                 `(while calling ,frobbotz)
                 `(received ,object))

     This might be printed as:

          Error: invalid argument
                 (not a pair)
                 (while calling #{Procedure 123 (frobbotz in ...)})
                 (received #(a b c d))

   The 'handle' structure exports the following procedures:

 -- procedure: with-handler handler thunk --> values
     Sets up HANDLER as the condition handler for the dynamic extent of
     THUNK.  HANDLER should be a procedure of two arguments: the
     condition that was signalled and a procedure of zero arguments that
     propagates the condition up to the next dynamically enclosing
     handler.  When a condition is signalled, HANDLER is tail-called
     from the point that the condition was signalled at.  Note that,
     because HANDLER is tail-called at that point, it will _return_ to
     that point also.

     *Warning:* 'With-handler' is potentially very dangerous.  If an
     exception occurs and a condition is raised in the handler, the
     handler itself will be called with that new condition!
     Furthermore, the handler may accidentally return to an unexpecting
     signaller, which can cause very confusing errors.  Be careful with
     'with-handler'; to be perfectly safe, it might be a good idea to
     throw back out to where the handler was initially installed before
     doing anything:

          ((call-with-current-continuation
             (lambda (k)
               (lambda ()
                 (with-handler (lambda (c propagate)
                                 (k (lambda () HANDLER BODY)))
                   (lambda () BODY))))))

 -- procedure: ignore-errors thunk --> values or condition
 -- procedure: report-errors-as-warnings thunk message irritant ... -->
          values
     'Ignore-errors' sets up a condition handler that will return error
     conditions to the point where 'ignore-errors' was called, and
     propagate all other conditions.  If no condition is signalled
     during the dynamic extent of THUNK, 'ignore-errors' simply returns
     whatever THUNK returned.  'Report-errors-as-warnings' downgrades
     errors to warnings while executing THUNK.  If an error occurs, a
     warning is signalled with the given message, and a list of
     irritants constructed by adding the error condition to the end of
     the list IRRITANT ....

   Finally, the 'simple-conditions' structure defines the condition type
system.  (Note that conditions themselves are constructed only by
'make-condition' (and 'signal') from the 'simple-signals' structure.)
Conditions are very basic values that have only two universally defined
fields: the type and the stuff.  The type is a symbol denoting a
condition type.  The type is specified in the first argument to
'make-condition' or 'signal'.  The stuff field contains whatever a
particular condition type stores in conditions of that type.  The stuff
field is always a list; it is created from the arguments after the first
to 'make-condition' or 'signal'.  Condition types are denoted by
symbols, kept in a global registry that maps condition type names to
their supertype names.

 -- procedure: define-condition-type name supertype-names -->
          unspecified
     Registers the symbol NAME as a condition type.  Its supertypes are
     named in the list SUPERTYPE-NAMES.

 -- procedure: condition-predicate ctype-name --> predicate
     Returns a procedure of one argument that returns '#t' if that
     argument is a condition whose type's name is CTYPE-NAME or '#f' if
     not.

 -- procedure: condition-type condition --> type-name
 -- procedure: condition-stuff condition --> list
     Accessors for the two immutable fields of conditions.

 -- procedure: error? condition --> boolean
 -- procedure: warning? condition --> boolean
 -- procedure: note? condition --> boolean
 -- procedure: syntax-error? condition --> boolean
 -- procedure: call-error? condition --> boolean
 -- procedure: read-error? condition --> boolean
 -- procedure: interrupt? condition --> boolean
     Condition predicates for built-in condition types.

 -- procedure: make-exception opcode reason arguments --> exception
 -- procedure: exception? condition --> boolean
 -- procedure: exception-opcode exception --> integer-opcode
 -- procedure: exception-reason exception --> symbol
 -- procedure: exception-arguments exception --> list
     "Exceptions" represent run-time errors in the Scheme48 VM. They
     contain information about what opcode the VM was executing when it
     happened, what the reason for the exception occurring was, and the
     relevant arguments.

4.2.2 Displaying conditions
---------------------------

The 'display-conditions' structure is also relevant in this section.

 -- procedure: display-condition condition port --> unspecified
     Prints CONDITION to PORT for a user to read.  For example:

          (display-condition (make-condition 'error
                               "Foo bar baz"
                               'quux
                               '(zot mumble: frotz))
                             (current-output-port))
              -| Error: Foo bar baz
              -|        quux
              -|        (zot mumble: frotz)

 -- method table: &disclose-condition condition --> disclosed
     Method table (*note Generic dispatch system::) for a generic
     procedure (not exposed) used to translate a condition object into a
     more readable format.  *Note Writer::.

 -- procedure: limited-write object port max-depth max-length -->
          unspecified
     A utility for avoiding excessive output: prints OBJECT to PORT, but
     will never print more than MAX-LENGTH of a subobject's components,
     leaving a '---' after the last component, and won't recur further
     down the object graph from the vertex OBJECT beyond MAX-DEPTH,
     instead printing an octothorpe ('#').

          (let ((x (cons #f #f)))
            (set-car! x x)
            (set-cdr! x x)
            (limited-write x (current-output-port) 2 2))
              -| ((# # ---) (# # ---) ---)

   ---------- Footnotes ----------

   (1) Note, however, that Scheme48's condition system is likely to be
superseded in the near future by [SRFI 34, SRFI 35].


File: scheme48.info,  Node: Bitwise manipulation,  Next: Generic dispatch system,  Prev: Condition system,  Up: System facilities

4.3 Bitwise manipulation
========================

Scheme48 provides two structures for bit manipulation: bitwise integer
operations, the 'bitwise' structure, and homogeneous vectors of bytes
(integers between 0 and 255, inclusive), the 'byte-vectors' structure.

4.3.1 Bitwise integer operations
--------------------------------

The 'bitwise' structure exports these procedures:

 -- procedure: bitwise-and integer ... --> integer
 -- procedure: bitwise-ior integer ... --> integer
 -- procedure: bitwise-xor integer ... --> integer
 -- procedure: bitwise-not integer --> integer
     Basic twos-complement bitwise boolean logic operations.

 -- procedure: arithmetic-shift integer count --> integer
     Shifts INTEGER by the given bit count.  If COUNT is positive, the
     shift is a left shift; otherwise, it is a right shift.
     'Arithmetic-shift' preserves INTEGER's sign.

 -- procedure: bit-count integer --> integer
     Returns the number of bits that are set in INTEGER.  If INTEGER is
     negative, it is flipped by the bitwise NOT operation before
     counting.

          (bit-count #b11010010)                  => 4

4.3.2 Byte vectors
------------------

The structure 'byte-vectors' exports analogues of regular vector
procedures for "byte vectors", homogeneous vectors of bytes:

 -- procedure: make-byte-vector length fill --> byte-vector
 -- procedure: byte-vector byte ... --> byte-vector
 -- procedure: byte-vector? object --> boolean
 -- procedure: byte-vector-length byte-vector --> integer
 -- procedure: byte-vector-ref byte-vector index --> byte
 -- procedure: byte-vector-set! byte-vector index byte --> unspecified
     FILL and each BYTE must be bytes, i.e. integers within the
     inclusive range 0 to 255.  Note that 'make-byte-vector' is not an
     exact analogue of 'make-vector', because the FILL parameter is
     required.

   Old versions of Scheme48 referred to byte vectors as 'code vectors'
(since they were used to denote byte code).  The 'code-vectors'
structure exports 'make-code-vector', 'code-vector?',
'code-vector-length', 'code-vector-ref', and 'code-vector-set!',
identical to the analogously named byte vector operations.


File: scheme48.info,  Node: Generic dispatch system,  Next: I/O system,  Prev: Bitwise manipulation,  Up: System facilities

4.4 Generic dispatch system
===========================

Scheme48 supports a CLOS-style generic procedure dispatch system, based
on type predicates.  The main interface is exported by 'methods'.  The
internals of the system are exposed by the 'meta-methods' structure, but
they are not documented here.  The generic dispatch system is used in
Scheme48's writer (*note Writer::) and numeric system.

   "Types" in Scheme48's generic dispatch system are represented using
type predicates, rather than having every object have a single,
well-defined 'class.'  The naming convention for simple types is to
prefix the type name with a colon.  The types support multiple
inheritance.  Method specificity is determined based on descending order
of argument importance.  That is, given two methods, M & N, such that
they are both applicable to a given sequence of arguments, and an index
I into that sequence, such that I is the first index in M's & N's lists
of argument type specifiers, from left to right, where the type differs:
if the type for M's argument at I is more specific than the
corresponding type in N's specifiers, M is considered to be more
specific than N, even if the remaining argument type specifiers in N are
more specific.

 -- syntax: define-simple-type name (supertype ...) predicate
     Defines NAME to be a "simple type" with the given predicate and the
     given supertypes.

 -- procedure: singleton value --> simple-type
     Creates a "singleton type" that matches only VALUE.

 -- syntax: define-generic proc-name method-table-name [prototype]
     Defines PROC-NAME to be a "generic procedure" that, when invoked,
     will dispatch on its arguments via the "method table" that
     METHOD-TABLE-NAME is defined to be and apply the most specific
     method it can determine defined in the METHOD-TABLE-NAME method
     table to its arguments.  The convention for naming variables that
     will be bound to method tables is to add an ampersand to the front
     of the name.  PROTOTYPE is a suggestion for what method prototypes
     should follow the shape of, but it is currently ignored.

 -- syntax: define-method method-table prototype body
     Adds a "method" to METHOD-TABLE, which is usually one defined by
     'define-generic'.(1)  PROTOTYPE should be a list whose elements may
     be either identifiers, in which case that parameter is not used for
     dispatching, or lists of two elements, the 'car' of which is the
     parameter name and the 'cadr' of which should evaluate to the type
     on which to dispatch.  As in many generic dispatch systems of
     similar designs, methods may invoke the next-most-specific method.
     By default, the name 'next-method' is bound in BODY to a nullary
     procedure that calls the next-most-specific method.  The name of
     this procedure may be specified by the user by putting the sequence
     '"next" NEXT-METHOD-NAME' in PROTOTYPE, in which case it will be
     NEXT-METHOD-NAME that is bound to that procedure.  For example:

          (define-method &frob ((foo :bar) "next" frobozz)
            (if (mumble? foo)
                (frobozz)     ; Invoke the next method.
                (yargh blargle foo)))

   A number of simple types are already defined & exported by the
'methods' structure.  Entries are listed as 'TYPE-NAME <- (SUPERTYPE
...), PREDICATE'

   * ':values <- (), (lambda (x) #t)' -- Abstract supertype of all
     run-time values

   * ':value <- (:values), (lambda (x) #t)' -- Abstract supertype of all
     first-class values

   * ':zero <- (:values), (lambda (x) #f)' -- Type that no objects
     satisfy

   * ':number <- (:value), number?'

   * ':complex <- (:number), complex?' -- (This happens to be equivalent
     to ':number'.)

   * ':real <- (:complex), real?'

   * ':rational <- (:real), rational?'

   * ':integer <- (:rational), integer?'

   * ':exact-integer <- (:integer), (lambda (x) (and (integer? x)
     (exact? x)))'

   * ':boolean <- (:value), boolean?'

   * ':symbol <- (:value), symbol?'

   * ':char <- (:value), char?'

   * ':null <- (:value), null?'

   * ':pair <- (:value), pair?'

   * ':vector <- (:value), vector?'

   * ':string <- (:value), string?'

   * ':procedure <- (:value), procedure?'

   * ':input-port <- (:value), input-port?'

   * ':output-port <- (:value), output-port?'

   * ':eof-object <- (:value), eof-object?'

   * ':record <- (:value), record?'

   ---------- Footnotes ----------

   (1) There is an internal interface, a sort of meta-object protocol,
to the method dispatch system, but it is not yet documented.


File: scheme48.info,  Node: I/O system,  Next: Reader & writer,  Prev: Generic dispatch system,  Up: System facilities

4.5 I/O system
==============

Scheme48 supports a sophisticated, non-blocking, user-extensible I/O
system untied to any particular operating system's I/O facilities.  It
is based in three levels: channels, ports, and the facilities already
built with both ports and channels in Scheme48, such as buffering.

* Menu:


* Ports::			Abstract & generalized I/O objects.
* Programmatic ports::		Designing custom ports.
* Miscellaneous I/O internals::	Various internal I/O system routines.
* Channels::			Low-level interface to OS facilities.
* Channel ports::		Ports built upon channels.


File: scheme48.info,  Node: Ports,  Next: Programmatic ports,  Up: I/O system

4.5.1 Ports
-----------

While channels provide the low-level interface directly to the OS's I/O
facilities, "ports" provide a more abstract & generalized mechanism for
I/O transmission.  Rather than being specific to channels or being
themselves primitive I/O devices, ports are functionally parameterized.
This section describes the usual I/O operations on ports.  The next
section describes the programmatic port parameterization mechanism, and
the section following that describes the most commonly used built-in
port abstraction, ports atop channels.

4.5.1.1 Port operations
.......................

The following names are exported by the 'i/o' structure.

 -- procedure: input-port? value --> boolean
 -- procedure: output-port? value --> boolean
     These return '#t' if their argument is both a port and either an
     input port or output port, respectively, or '#f' if neither
     condition is true.

 -- procedure: close-input-port port --> unspecified
 -- procedure: close-output-port port --> unspecified
     Closes PORT, which must be an input port or an output port,
     respectively.

 -- procedure: char-ready? [port] --> boolean
 -- procedure: output-port-ready? port --> boolean
     'Char-ready?' returns a true value if there is a character ready to
     be read from PORT and '#f' if there is no character ready.  PORT
     defaults to the current input port if absent; see below on current
     ports.  'Output-port-ready?' returns a true value if PORT is ready
     to receive a single written character and '#f' if not.

 -- procedure: read-block block start count port [wait?] --> count-read
          or EOF
 -- procedure: write-block block start count port --> count-written
 -- procedure: write-string string port --> char-count-written
     'Read-block' attempts to read COUNT elements from PORT into BLOCK,
     which may be a string or a byte vector, starting at START.  If
     fewer than COUNT characters or bytes are available to read from
     PORT, and WAIT? is a true value or absent, 'read-block' will wait
     until COUNT characters are available and read into BLOCK; if WAIT?
     is '#f', 'read-block' immediately returns.  'Read-block' returns
     the number of elements read into BLOCK, or an end of file object if
     the stream's end is immediately encountered.  'Write-block' writes
     COUNT elements from BLOCK, which may be a string or a byte vector,
     starting at START to PORT.  'Write-string' is a convenience atop
     'write-block' for writing the entirety of a string to a port.

 -- procedure: newline [port] --> unspecified
     Writes a newline character or character sequence to the output port
     PORT.  PORT defaults to the current output port; see below on
     current ports.

 -- procedure: disclose-port port --> disclosed
     Returns a disclosed representation of PORT; *note Writer::.

 -- procedure: force-output port --> unspecified
     Forces all buffered output in the output port PORT to be sent.

 -- procedure: make-null-output-port --> output-port
     Returns an output port that will ignore any output it receives.

4.5.1.2 Current ports
.....................

Scheme48 keeps in its dynamic environment (*note Fluid/dynamic
bindings::) a set of 'current' ports.  These include R5RS's current
input and output ports, as well as ports for general noise produced by
the system, and ports for where error messages are printed.  These
procedures are exported by the 'i/o' structure.

 -- procedure: current-input-port --> input-port
 -- procedure: current-output-port --> output-port
 -- procedure: current-noise-port --> output-port
 -- procedure: current-error-port --> output-port
     These return the values in the current dynamic environment of the
     respective ports.  'Current-input-port' and 'current-output-port'
     are also exported by the 'scheme' structure.

 -- procedure: input-port-option arguments --> input-port
 -- procedure: output-port-option arguments --> output-port
     These are utilities for retrieving optional input and output port
     arguments from rest argument lists, defaulting to the current input
     or output ports.  For example, assuming the newline character
     sequence is simply '#\newline', 'newline' might be written as:

          (define (newline . maybe-port)
            (write-char #\newline (output-port-option maybe-port)))

 -- procedure: silently thunk --> values
     This stifles output from the current noise port in the dynamic
     extent of THUNK, which is applied to zero arguments.  'Silently'
     returns the values that THUNK returns.

 -- procedure: with-current-ports input output error thunk --> values
     'With-current-ports' dynamically binds the current input, output,
     and error ports to INPUT, OUTPUT, and ERROR, respectively, in the
     dynamic extent of THUNK, which is applied to zero arguments.  The
     current noise port is also bound to ERROR.  'With-current-ports'
     returns the values that THUNK returns.

   Similarly to 'with-current-ports', the 'i/o-internal' structure also
exports these procedures:

 -- procedure: call-with-current-input-port port thunk --> values
 -- procedure: call-with-current-output-port port thunk --> values
 -- procedure: call-with-current-noise-port port thunk --> values
     These bind individual current ports for the dynamic extent of each
     THUNK, which is applied to zero arguments.  These all return the
     values that THUNK returns.


File: scheme48.info,  Node: Programmatic ports,  Next: Miscellaneous I/O internals,  Prev: Ports,  Up: I/O system

4.5.2 Programmatic ports
------------------------

Ports are user-extensible; all primitive port operations on them --
'read-char', 'write-block', &c. -- are completely generalized.
Abstractions for buffered ports are also available.

* Menu:


* Port data type::
* Port handlers::
* Buffered ports & handlers::


File: scheme48.info,  Node: Port data type,  Next: Port handlers,  Up: Programmatic ports

4.5.2.1 Port data type
......................

The 'ports' structure defines the basis of the port data type and
exports the following procedures.

 -- procedure: make-port handler status lock data buffer index limit
          pending-eof? --> port
     Port constructor.  The arguments are all the fields of ports, which
     are described below.  Note that 'make-port' is rarely called
     directly; usually one will use one of the buffered port
     constructors instead.

 -- procedure: port-handler port --> port-handler
 -- procedure: port-buffer port --> buffer or '#f'
 -- procedure: port-lock port --> value
 -- procedure: port-status port --> integer-status
 -- procedure: port-data port --> value
 -- procedure: port-index port --> integer or '#f'
 -- procedure: port-limit port --> integer or '#f'
 -- procedure: port-pending-eof? port --> boolean
     Accessors for the port fields:

     'handler'
          The handler is the functional parameterization mechanism: it
          provides all the port's operations, such as reading/writing
          blocks, disclosing (*note Writer::) the port, closing the
          port, &c.  *Note Port handlers::.

     'buffer'
          The buffer is used for buffered ports, where it is a byte
          vector (*note Bitwise manipulation::).  It may be any value
          for unbuffered ports.

     'lock'
          This misnamed field was originally used for a mutual exclusion
          lock, before optimistic concurrency was made the native
          synchronization mechanism in Scheme48.  It is now used as a
          'timestamp' for buffered ports: it is provisionally written to
          with a unique value when a thread resets the 'index' to reüse
          the buffer, and it is provisionally read from when reading
          from the buffer.  In this way, if the buffer is reset while
          another thread is reading from it, the other thread's proposal
          is invalidated by the different value in memory than what was
          there when it logged the old timestamp in its proposal.

     'status'
          A mask from the 'port-status-options' enumeration; *note
          Miscellaneous I/O internals::.

     'data'
          Arbitrary data for particular kinds of ports.  For example,
          for a port that tracks line & column information (*note I/O
          extensions::), this might be a record containing the
          underlying port, the line number, and the column number.

     'index'
          The current index into a buffered port's buffer.  If the port
          is not buffered, this is '#f'.

     'limit'
          The limit of the 'index' field for a buffered port's buffer.
          When the 'index' field is equal to the 'limit' field, the
          buffer is full.  If the port is not buffered, this is '#f'.

     'pending-eof?'
          For output ports, this is a boolean flag indicating whether
          the buffer has been forced to output recently.  For input
          ports, this is a boolean flag indicating whether an end of
          file is pending after reading through the current buffer.

 -- procedure: set-port-lock! port value --> unspecified
 -- procedure: set-port-status! port status --> unspecified
 -- procedure: set-port-data! port data --> unspecified
 -- procedure: set-port-index! port index --> unspecified
 -- procedure: set-port-limit! port index --> unspecified
 -- procedure: set-port-pending-eof?! port pending-eof? --> unspecified
     These assign respective fields of ports.  The 'buffer' and
     'handler' fields, however, are immutable.

 -- procedure: provisional-port-handler port --> port-handler
 -- procedure: provisional-port-lock port --> value
 -- procedure: provisional-port-status port --> integer-status
 -- procedure: provisional-port-data port --> value
 -- procedure: provisional-port-index port --> integer or '#f'
 -- procedure: provisional-port-limit port --> integer or '#f'
 -- procedure: provisional-port-pending-eof? port --> boolean
 -- procedure: provisional-set-port-lock! port value --> unspecified
 -- procedure: provisional-set-port-status! port status --> unspecified
 -- procedure: provisional-set-port-data! port data --> unspecified
 -- procedure: provisional-set-port-index! port index --> unspecified
 -- procedure: provisional-set-port-limit! port index --> unspecified
 -- procedure: provisional-set-port-pending-eof?! port pending-eof? -->
          unspecified
     Provisional versions of the above port accessors & modifiers; that
     is, accessors & modifiers that log in the current proposal, if
     there is one.


File: scheme48.info,  Node: Port handlers,  Next: Buffered ports & handlers,  Prev: Port data type,  Up: Programmatic ports

4.5.2.2 Port handlers
.....................

"Port handlers" store a port's specific operations for the general port
operations, such as block reads and writes, buffer flushing, &c.  Port
handler constructors, including 'make-port-handler' & the buffered port
handlers in the next section, are available from the 'i/o-internal'
structure.

 -- procedure: make-port-handler discloser closer char-reader/writer
          block-reader/writer readiness-tester buffer-forcer -->
          port-handler
     Basic port handler constructor.  The arguments are used for the
     port handler fields.  Each field contains a procedure.  The
     expected semantics of each procedure depend on whether the port is
     for input or output.  Input ports do not use the 'buffer-forcer'
     field.  The first two fields are independent of the type of port:

     discloser port -> disclosed
          Returns a disclosed representation of the port, i.e. a list
          whose 'car' is the 'type name' of this handler (usually with a
          suffix of either '-input-port' or '-output-port') followed by
          a list of all of the components to be printed; *note Writer::.

     closer port -> ignored
          Closes PORT.  This operation corresponds with the
          'close-input-port' & 'close-output-port' procedures.

     For input ports, the remaining fields are:

     char-reader port consume? -> char
          Reads a single character from PORT.  If CONSUME? is true, the
          character should be consumed from PORT; if CONSUME? is '#f',
          however, the character should be left in PORT's input stream.
          If CONSUME? is true, this operation corresponds with
          'read-char'; if it is '#f', this operation corresponds with
          'peek-char'.

     block-reader port block start count wait? -> count-written or EOF
          Attempts to read COUNT characters from PORT's input stream
          into the string or byte vector BLOCK, starting at START.  In
          the case that an insufficient number of characters is
          available, if WAIT? is true, the procedure should wait until
          all of the wanted characters are available; otherwise, if
          WAIT? is '#f', the block reader should immediately return.  In
          either case, it returns the number of characters that were
          read into BLOCK, or an end of file object if it immediately
          reached the end of the stream.  Buffered ports will typically
          just copy elements from the buffer into BLOCK, rather than
          reading from any internal I/O channel in PORT.  This operation
          corresponds with 'read-block'.

     readiness-tester port -> boolean
          Returns a true value if there is a character available to be
          read in PORT or '#f' if not.  This operation corresponds with
          the 'char-ready?' procedure.

     For output ports, the remaining fields are:

     char-writer port char -> ignored
          Writes the single character CHAR to PORT.  This operation
          corresponds with 'write-char'.

     block-writer port block start count -> count-written
          Writes COUNT characters to PORT from BLOCK, starting at START.
          BLOCK may be a string or a byte vector.  This will usually
          involve copying contents of BLOCK to PORT's buffer, if it is
          buffered.  This operation corresponds with 'write-block'.

     readiness-tester port -> boolean
          Returns a true value if PORT is ready to receive a character
          and '#f' if not.

     buffer-forcer port necessary? -> ignored
          For buffered ports, this is intended to force all buffered
          output to the actual internal I/O channel of PORT.  NECESSARY?
          tells whether or not it is absolutely necessary to force all
          the output immediately; if it is '#t', the buffer forcer is
          required to force all output in the buffer before it returns.
          If NECESSARY? is '#f', not only may it just register an I/O
          transaction without waiting for it to complete, but it also
          should _not_ signal an error if PORT is already closed.  For
          unbuffered ports, this operation need not do anything at all.


File: scheme48.info,  Node: Buffered ports & handlers,  Prev: Port handlers,  Up: Programmatic ports

4.5.2.3 Buffered ports & handlers
.................................

Along with bare port handlers, Scheme48 provides conveniences for many
patterns of buffered ports & port handlers.  These names are exported by
the 'i/o-internal' structure.  Buffered ports are integrated with
Scheme48's optimistic concurrency (*note Optimistic concurrency::)
facilities.

   *Note:* Although internally buffered ports are integrated with
optimistic concurrency, operations on buffered ports, like operations on
channels, cannot be reliably fusibly atomic.

 -- procedure: make-buffered-input-port handler data buffer index limit
          --> input-port
 -- procedure: make-buffered-output-port handler data buffer index limit
          --> output-port
     Constructors for buffered ports.  HANDLER is the port's handler,
     which is usually constructed with one of the buffered port handler
     constructors (see below).  DATA is arbitrary data to go in the
     port's 'data' field.  BUFFER is a byte vector whose length is
     greater than or equal to both INDEX & LIMIT.  INDEX is the initial
     index into BUFFER to go in the port's 'index' field.  LIMIT is the
     limit in the port's buffer, to go into the port's 'limit' field;
     nothing will be written into BUFFER at or past LIMIT.

 -- procedure: make-unbuffered-input-port handler data --> input-port
 -- procedure: make-unbuffered-output-port handler data --> output-port
     Conveniences for ports that are explicitly _not_ buffered.  Only
     the relevant fields are passed; all fields pertaining to buffering
     are initialized with '#f'.

 -- procedure: make-buffered-input-port-handler discloser closer
          buffer-filler readiness-tester --> port-handler
     This creates a port handler for buffered input ports.  The
     arguments are as follows:

     discloser port-data -> disclosed
     closer port-data -> ignored
          DISCLOSER & CLOSER are like the similarly named regular port
          handler fields, but they are applied directly to the port's
          data, not to the port itself.

     buffer-filler port wait? -> committed?
          Used to fill PORT's buffer when it no longer has contents from
          which to read in its current buffer.  WAIT? is a boolean flag,
          '#t' if the operation should wait until the I/O transaction
          necessary to fill the buffer completes, or '#f' if it may
          simply initiate an I/O transaction but not wait until it
          completes (e.g., use 'channel-maybe-commit-and-read', but not
          wait on the condition variable passed to
          'channel-maybe-commit-and-read').  BUFFER-FILLER is called
          with a fresh proposal in place, and it is the responsibility
          of BUFFER-FILLER to commit it.  It returns a boolean flag
          denoting whether the proposal was committed.  The last call in
          BUFFER-FILLER is usually either '(maybe-commit)' or a call to
          a procedure that causes that effect (e.g., one of the
          operation on condition variables that commits the current
          proposal.  *Note condition variables: Higher-level
          synchronization.)

     readiness-tester port -> [committed? ready?]
          Called when 'char-ready?' is applied to PORT and the buffer of
          PORT is empty.  Like BUFFER-FILLER, READINESS-TESTER is
          applied with a fresh proposal in place, which it should
          attempt to commit.  READINESS-TESTER should return two values,
          each a boolean flag: the first denotes whether or not the
          current proposal was successfully committed, and, if it was
          successful, whether or not a character is ready.

 -- procedure: make-buffered-output-port-handler discloser
          buffer-emptier readiness-tester --> port-handler
     This creates a port handler for buffered output ports.  DISCLOSER &
     CLOSER are as with buffered input ports.  The remaining fields are
     as follows:

     buffer-emptier port necessary? -> committed?
          BUFFER-EMPTIER is used when PORT's buffer is full and needs to
          be emptied.  It is called with a fresh proposal in place.  It
          should reset PORT's 'index' field, call 'note-buffer-reuse!'
          to invalidate other threads' transactions on the recycled
          buffer, and attempt to commit the new proposal installed.  It
          returns a boolean flag indicating whether or not the commit
          succeeded.

     readiness-tester port -> [committed? ready?]
          READINESS-TESTER is applied to PORT when its buffer is full
          (i.e. its 'index' & 'limit' fields are equal) and
          'output-port-ready?' is applied to PORT.  After performing the
          test, it should attempt to commit the current proposal and
          then return two values: whether it succeeded in committing the
          current proposal, and, if it was successful, whether or not a
          character is ready to be outputted.

 -- constant: default-buffer-size --> integer
     The default size for port buffers.  This happens to be 4096 in the
     current version of Scheme48.

 -- procedure: note-buffer-reuse! port --> unspecified
 -- procedure: check-buffer-timestamp! port --> unspecified
     These are used to signal the resetting of a buffer between multiple
     threads.  'Note-buffer-reuse!' is called -- in the case of an
     output port -- when a buffer fills up, is emptied, and flushed; or
     -- in the case of an input port -- when a buffer is emptied and
     needs to be refilled.  'Note-buffer-reuse!' logs in the current
     proposal a fresh value to store in PORT.  When that proposal is
     committed, this fresh value is stored in the port.  Other threads
     that were using PORT's buffer call 'check-buffer-timestamp!', which
     logs a read in the current proposal.  If another thread commits a
     buffer reüse to memory, that read will be invalidated, invalidating
     the whole transaction.


File: scheme48.info,  Node: Miscellaneous I/O internals,  Next: Channels,  Prev: Programmatic ports,  Up: I/O system

4.5.3 Miscellaneous I/O internals
---------------------------------

All of these but 'port-status-options' are exported by the
'i/o-internal' structure; the 'port-status-options' enumeration is
exported by the 'architecture' structure, but it deserves mention in
this section.

 -- enumeration: port-status-options
          (define-enumeration port-status-options
            (input
             output
             open-for-input
             open-for-output))
     Enumeration of indices into a port's 'status' field bit set.

 -- procedure: open-input-port? port --> boolean
 -- procedure: open-output-port? port --> boolean
     These return true values if PORT is both an input or output port,
     respectively, and open.

 -- constant: open-input-port-status --> integer-status
 -- constant: open-output-port-status --> integer-status
     The bitwise masks of enumerands from the 'port-status-options'
     enumeration signifying an open input or output port, respectively.

 -- procedure: make-input-port-closed! port --> unspecified
 -- procedure: make-output-port-closed! port --> unspecified
     These set the status of PORT, which must be an input or output
     port, respectively, to indicate that it is closed.

 -- procedure: eof-object --> eof-object
     Returns the EOF object token.  This is the only value that will
     answer true to R5RS's 'eof-object?' predicate.

 -- procedure: force-output-if-open port --> unspecified
     This forces PORT's output if it is an open output port, and does
     not block.

 -- procedure: periodically-force-output! port --> unspecified
 -- procedure: periodically-flushed-ports --> port-list
     'Periodically-force-output!' registers PORT to be forced
     periodically.  Only a weak reference to PORT in this registry is
     held, however, so this cannot cause accidental space leaks.
     'Periodically-flushed-ports' returns a list of all ports in this
     registry.  Note that the returned list holds strong references to
     all of its elements.  'Periodically-flushed-ports' does not permit
     thread context switches, or interrupts of any sort, while it runs.


File: scheme48.info,  Node: Channels,  Next: Channel ports,  Prev: Miscellaneous I/O internals,  Up: I/O system

4.5.4 Channels
--------------

"Channels" represent the OS's native I/O transmission channels.  On
Unix, channels are essentially boxed file descriptors, for example.  The
only operations on channels are block reads & writes.  Blocks in this
sense may be either strings or byte vectors (*note Bitwise
manipulation::).

4.5.4.1 Low-level channel operations
....................................

The low-level base of the interface to channels described here is
exported from the 'channels' structure.

 -- procedure: channel? --> boolean
     Disjoint type predicate for channels.

 -- procedure: channel-id channel --> value
 -- procedure: channel-status channel --> integer-enumerand
 -- procedure: channel-os-index channel --> integer
     'Channel-id' returns CHANNEL's id.  The id is some identifying
     characteristic of channels.  For example, file channels' ids are
     usually the corresponding filenames; channels such as the standard
     input, output, or error output channels have names like '"standard
     input"' and '"standard output"'.  'Channel-status' returns the
     current status of CHANNEL; see the 'channel-status-option'
     enumeration below.  'Channel-os-index' returns the OS-specific
     integer index of CHANNEL.  On Unix, for example, this is the
     channel's file descriptor.

 -- procedure: open-channel filename option close-silently? --> channel
     'Open-channel' opens a channel for a file given its filename.
     OPTION specifies what type of channel this is; see the
     'channel-status-option' enumeration below.  CLOSE-SILENTLY? is a
     boolean that specifies whether a message should be printed (on
     Unix, to 'stderr') when the resulting channel is closed after a
     garbage collector finds it unreachable.

 -- procedure: close-channel channel --> unspecified
     Closes CHANNEL after aborting any potential pending I/O
     transactions it may have been involved with.

 -- procedure: channel-ready? channel --> boolean
     If CHANNEL is an input channel: returns '#t' if there is input
     ready to be read from CHANNEL or '#f' if not; if CHANNEL is an
     output channel: returns '#t' if a write would immediately take
     place upon calling 'channel-maybe-write', i.e.
     'channel-maybe-write' would not return '#f', or '#f' if not.

 -- procedure: channel-maybe-read channel buffer start-index octet-count
          wait? --> octet count read, error status cell, EOF object, or
          '#f'
 -- procedure: channel-maybe-write channel buffer start-index
          octet-count --> octet count written, error status cell, or
          '#f'
 -- procedure: channel-abort channel --> unspecified
     'Channel-maybe-read' attempts to read OCTET-COUNT octets from
     CHANNEL into BUFFER, starting at START-INDEX.  If a low-level I/O
     error occurs, it returns a cell containing a token given by the
     operating system indicating what kind of error occurred.  If WAIT?
     is '#t', and CHANNEL is not ready to be read from, CHANNEL is
     registered for the VM's event polling mechanism, and
     'channel-maybe-read' returns '#f'.  Otherwise, it returns either
     the number of octets read, or an EOF object if CHANNEL was was at
     the end.

     'Channel-maybe-write' attempts to write OCTET-COUNT octets to
     CHANNEL from BUFFER, starting at START-INDEX.  If a low-level I/O
     error occurs, it returns a cell indicating a token given by the
     operating system indicating what kind of error occurred.  If no
     such low-level error occurs, it registers CHANNEL for the VM's
     event polling mechanism and returns '#f' iff zero octets were
     immediately written or the number of octets immediately written if
     any were.

     'Channel-abort' aborts any pending operation registered for the
     VM's event polling mechanism.

 -- procedure: open-channels-list --> channel-list
     Returns a list of all open channels in order of the 'os-index'
     field.

 -- enumeration: channel-status-option
          (define-enumeration channel-status-option
            (closed
             input
             output
             special-input
             special-output))
     Enumeration for a channel's status.  The 'closed' enumerand is used
     only after a channel has been closed.  Note that this is _not_
     suitable for a bit mask; that is, one may choose exactly one of the
     enumerands, not use a bit mask of status options.  For example, to
     open a file 'frob' for input that one wishes the garbage collector
     to be silent about on closing it:

          (open-channel "frob"
                        (enum channel-status-option input)
                        #t)
              => #{Input-channel "frob"}

4.5.4.2 Higher-level channel operations
.......................................

More convenient abstractions for operating on channels, based on
condition variables (*note Higher-level synchronization::), are provided
from the 'channel-i/o' structure.  They are integrated with Scheme48's
optimistic concurrency (*note Optimistic concurrency::) facilities.

   *Note:* Transactions on channels can _not_ be atomic in the sense of
optimistic concurrency.  Since they involve communication with the
outside world, they are irrevocable transactions, and thus an
invalidated proposal cannot retract the transaction on the channel.

 -- procedure: channel-maybe-commit-and-read channel buffer start-index
          octet-count condvar wait? --> committed?
 -- procedure: channel-maybe-commit-and-write channel buffer start-index
          octet-count condvar --> committed?
     These attempt to commit the current proposal.  If they fail, they
     immediately return '#f'; otherwise, they proceed, and return '#t'.
     If the commit succeeded, these procedures attempt an I/O
     transaction, without blocking.  'Channel-maybe-commit-and-read'
     attempts to read OCTET-COUNT octets into BUFFER, starting at
     START-INDEX, from CHANNEL.  'Channel-maybe-commit-and-write'
     attempts to write OCTET-COUNT octets from BUFFER, starting at
     START-INDEX, to CHANNEL.  CONDVAR is noted as waiting for the
     completion of the I/O transaction.  When the I/O transaction
     finally completes -- in the case of a read, there are octets ready
     to be read into BUFFER from CHANNEL or the end of the file was
     struck; in the case of a write, CHANNEL is ready to receive some
     octets --, CONDVAR is set to the result of the I/O transaction: the
     number of octets read, an I/O error condition, or an EOF object,
     for reads; and the number of octets written or an I/O error
     condition, for writes.

 -- procedure: channel-maybe-commit-and-close channel closer -->
          committed?
     Attempts to commit the current proposal; if successful, this aborts
     any wait on CHANNEL, sets the result of any condvars waiting on
     CHANNEL to the EOF object, closes CHANNEL by applying CLOSER to
     CHANNEL (in theory, CLOSER could be anything; usually, however, it
     is 'close-channel' from the 'channels' structure or some wrapper
     around it), and returns '#t'.  If the commit failed,
     'channel-maybe-commit-and-close' immediately returns '#f'.

 -- procedure: channel-write channel buffer start-index octet-count -->
          octet-count-written
     Atomically attempts to write OCTET-COUNT octets to CHANNEL from
     BUFFER, starting at START-INDEX in BUFFER.  If no I/O transaction
     immediately occurs -- what would result in 'channel-maybe-write'
     returning '#f' --, 'channel-write' blocks until something does
     happen.  It returns the number of octets written to CHANNEL.

 -- procedure: wait-for-channel channel condvar --> unspecified
     Registers CONDVAR so that it will be set to the result of some
     prior I/O transaction when some I/O event regarding CHANNEL occurs.
     (Contrary to the name, this does not actually wait or block.  One
     must still use 'maybe-commit-and-wait-for-condvar' on CONDVAR;
     *note condition variables: Higher-level synchronization.)  This is
     useful primarily in conjunction with calling foreign I/O routines
     that register channels with the VM's event polling system.

     *Note:* 'wait-for-channel' must be called with interrupts disabled.


File: scheme48.info,  Node: Channel ports,  Prev: Channels,  Up: I/O system

4.5.5 Channel ports
-------------------

Built-in to Scheme48 are ports made atop channels.  These are what are
created by R5RS's standard file operations.  The following names are
exported by the 'channel-ports' structure.

 -- procedure: call-with-input-file filename receiver --> values
 -- procedure: call-with-output-file filename receiver --> values
 -- procedure: with-input-from-file filename thunk --> values
 -- procedure: with-output-to-file filename thunk --> values
 -- procedure: open-input-file filename --> input-port
 -- procedure: open-output-file filename --> output-port
     Standard R5RS file I/O operations.  (These are also exported by the
     'scheme' structure.)  The 'call-with-...put-file' operations open
     the specified type of port and apply RECEIVER to it; after RECEIVER
     returns normally (i.e. nothing is done if there is a throw out of
     RECEIVER), they close the port and return the values that RECEIVER
     returned.  'With-input-from-file' & 'with-output-to-file' do
     similarly, but, rather than applying THUNK to the port, they
     dynamically bind the current input & output ports, respectively, to
     the newly opened ports.  'Call-with-input-file',
     'call-with-output-file', 'with-input-from-file', and
     'with-output-to-file' return the values that THUNK returns.
     'Open-input-file' & 'open-output-file' just open input & output
     ports; users of these operations must close them manually.

 -- procedure: input-channel->port channel [buffer-size] --> port
 -- procedure: output-channel->port channel [buffer-size] --> port
     These create input & output ports atop the given channels and
     optional buffer sizes.  The default buffer size is 4096 bytes.

 -- procedure: input-channel+closer->port channel closer [buffer-size]
          --> port
 -- procedure: output-channel+closer->port channel closer [buffer-size]
          --> port
     Similarly, these create input & output ports atop the given
     channels and optional buffer sizes, but they allow for extra
     cleanup when the resulting ports are closed.

 -- procedure: port->channel port --> channel or '#f'
     If PORT is a port created by the system's channel ports facility,
     'port->channel' returns the channel it was created atop; otherwise
     'port->channel' returns '#f'.

 -- procedure: force-channel-output-ports! --> unspecified
     This attempts to force as much output as possible from all of the
     ports based on channels.  This is used by Scheme48's POSIX
     libraries before forking the current process.


File: scheme48.info,  Node: Reader & writer,  Next: Records,  Prev: I/O system,  Up: System facilities

4.6 Reader & writer
===================

Scheme48 has simple S-expression reader & writer libraries, with some
facilities beyond R5RS's 'read' & 'write' procedures.

* Menu:


* Reader::
* Writer::


File: scheme48.info,  Node: Reader,  Next: Writer,  Up: Reader & writer

4.6.1 Reader
------------

Scheme48's reader facility is exported by the 'reading' structure.  The
'read' binding thereby exported is identical to that of the 'scheme'
structure, which is the binding that R5RS specifies under the name
'read'.

 -- procedure: read [port] --> readable-value
     Reads a single S-expression from PORT, whose default value is the
     current input port.  If the end of the stream is encountered before
     the beginning of an S-expression, 'read' will return an EOF object.
     It will signal a read error if text read from PORT does not
     constitute a complete, well-formed S-expression.

 -- procedure: define-sharp-macro char proc --> unspecified
     Defines a sharp/pound/hash/octothorpe ('#') reader macro.  The next
     time the reader is invoked, if it encounters an octothorpe/sharp
     followed by CHAR, it applies PROC to CHAR and the input port being
     read from.  CHAR is _not_ consumed in the input port.  If CHAR is
     alphabetic, it should be lowercase; otherwise the reader will not
     recognize it, since the reader converts the character following
     octothorpes to lowercase.

 -- procedure: reading-error port message irritant ... --> unspecified
     Signals an error while reading, for custom sharp macros.  It is not
     likely that calls to 'reading-error' will return.

 -- procedure: gobble-line port --> unspecified
     Reads until a newline from PORT.  The newline character sequence is
     consumed.


File: scheme48.info,  Node: Writer,  Prev: Reader,  Up: Reader & writer

4.6.2 Writer
------------

Scheme48's 'writing' structure exports its writer facility.  The 'write'
and 'display' bindings from it are identical to those from the 'scheme'
structure, which are the same bindings that R5RS specifies.

 -- procedure: write object [port] --> unspecified
     Writes OBJECT to PORT, which defaults to the current output port,
     in a machine-readable manner.  Strings are written with double-
     quotes; characters are prefixed by '#\'.  Any object that is
     unreadable -- anything that does not have a written representation
     as an S-expression -- is written based on its "disclosed"
     representation.  Such unreadable objects are converted to a
     disclosed representation by the 'disclose' generic procedure (see
     below).

 -- procedure: display object [port] --> unspecified
     Displays OBJECT to PORT, which defaults to the value of the current
     output port, in a more human-readable manner.  Strings are written
     without surrounding double-quotes; characters are written as
     themselves with no prefix.

 -- procedure: recurring-write object port recur --> unspecified
     Writes OBJECT to PORT.  Every time this recurs upon a new object,
     rather than calling itself or its own looping procedure, it calls
     RECUR.  This allows customized printing routines that still take
     advantage of the existence of Scheme48's writer.  For example,
     'display' simply calls 'recurring-write' with a recurring procedure
     that prints strings and characters specially and lets
     'recurring-write' handle everything else.

 -- procedure: display-type-name name port --> unspecified
     If NAME is a symbol with an alphabetic initial character, this
     writes NAME to PORT with the first character uppercased and the
     remaining character lowercased; otherwise, 'display-type-name'
     simply writes NAME to PORT with 'display'.

          (display-type-name 'foo)
              -| Foo

          (display-type-name (string->symbol "42foo"))
              -| 42foo

          (display-type-name (cons "foo" "bar"))
              -| (foo . bar)

          (display-type-name (string->symbol "fOo-BaR"))
              -| Foo-bar

     This is used when printing disclosed representations (see below).

4.6.2.1 Object disclosure
.........................

The 'methods' structure (*note Generic dispatch system::) exports the
generic procedure 'disclose' and its method table '&disclose'.  When
'recurring-write' encounters an object it is unable to write in a
rereadable manner, it applies 'disclose' to the unreadable object to
acquire a "disclosed representation."  (If 'disclose' returns '#f', i.e.
the object has no disclosed representation, the writer will write
'#{Random object}'.)  After converting a value to its disclosed
representation, e.g. a list consisting of the symbol 'foo', the symbol
'bar', a byte vector, and a pair '(1 . 2)', the writer will write '#{Foo
#{Byte-vector} bar (1 . 2)}'.  That is: contents of the list are
surrounded by '#{' and '}', the first element of the list (the 'type
name') is written with 'display-type-name', and then the remaining
elements of the list are recursively printed out with the RECUR
argument.

   Typically, when a programmer creates an abstract data type by using
Scheme48's record facility, he will not add methods to '&disclose' but
instead define the record type's discloser with the
'define-record-discloser' procedure; *note Records::.

   Example:

     (define-record-type pare rtd/pare
       (kons a d)
       pare?
       (a kar set-kar!)
       (d kdr set-kdr!))

     (define-record-discloser rtd/pare
       (lambda (pare)
         `(pare ,(kar pare) *dot* ,(kdr pare))))

     (write (kons (kons 5 3) (kons 'a 'b)))
         -| #{Pare #{Pare 5 *dot* 3} *dot* #{Pare a *dot* b}}


File: scheme48.info,  Node: Records,  Next: Suspending and resuming heap images,  Prev: Reader & writer,  Up: System facilities

4.7 Records
===========

Scheme48 provides several different levels of a record facility.  Most
programmers will probably not care about the two lower levels; the
syntactic record type definers are sufficient for abstract data types.

   At the highest level, there are two different record type definition
macros.  Richard Kelsey's is exported from the 'defrecord' structure;
Jonathan Rees's is exported from 'define-record-types'.  They both
export a 'define-record-type' macro and the same
'define-record-discloser' procedure; however, the macros are
dramatically different.  Scheme48 also provides [SRFI 9], which is
essentially Jonathan Rees's record type definition macro with a slight
syntactic difference, in the 'srfi-9' structure.  Note, however, that
'srfi-9' does not export 'define-record-discloser'.  The difference
between Jonathan Rees's and Richard Kelsey's record type definition
macros is merely syntactic convenience; Jonathan Rees's more
conveniently allows for arbitrary naming of the generated variables,
whereas Richard Kelsey's is more convenient if the naming scheme varies
little.

4.7.1 Jonathan Rees's 'define-record-type' macro
------------------------------------------------

 -- syntax: define-record-type
          (define-record-type RECORD-TYPE-NAME RECORD-TYPE-VARIABLE
            (CONSTRUCTOR CONSTRUCTOR-ARGUMENT ...)
            [PREDICATE]
            (FIELD-TAG FIELD-ACCESSOR [FIELD-MODIFIER])
            ...)
     This defines RECORD-TYPE-VARIABLE to be a record type descriptor.
     CONSTRUCTOR is defined to be a procedure that accepts the listed
     field arguments and creates a record of the newly defined type with
     those fields initialized to the corresponding arguments.
     PREDICATE, if present, is defined to be the disjoint (as long as
     abstraction is not violated by the lower-level record interface)
     type predicate for the new record type.  Each FIELD-ACCESSOR is
     defined to be a unary procedure that accepts a record type and
     returns the value of the field named by the corresponding
     FIELD-TAG.  Each FIELD-MODIFIER, if present, is defined to be a
     binary procedure that accepts a record of the new type and a value,
     which it assigns the field named by the corresponding FIELD-TAG to.
     Every CONSTRUCTOR-ARGUMENT must have a corresponding FIELD-TAG,
     though FIELD-TAGs that are not used as arguments to the record
     type's constructor are simply uninitialized when created.  They
     should have modifiers: otherwise they will never be initialized.

     It is worth noting that Jonathan Rees's 'define-record-type' macro
     does not introduce identifiers that were not in the original
     macro's input form.

     For example:

          (define-record-type pare rtd/pare
            (kons a d)
            pare?
            (a kar)
            (d kdr set-kdr!))

          (kar (kons 5 3))
              => 5

          (let ((p (kons 'a 'c)))
            (set-kdr! p 'b)
            (kdr p))
              => b

          (pare? (kons 1 2))
              => #t

          (pare? (cons 1 2))
              => #f

   There is also a variant of Jonathan Rees's 'define-record-type' macro
for defining record types with fields whose accessors and modifiers
respect optimistic concurrency (*note Optimistic concurrency::) by
logging in the current proposal.

4.7.2 Richard Kelsey's 'define-record-type' macro
-------------------------------------------------

 -- syntax: define-record-type
          (define-record-type TYPE-NAME
            (ARGUMENT-FIELD-SPECIFIER ...)
            (NONARGUMENT-FIELD-SPECIFIER ...))

              ARGUMENT-FIELD-SPECIFIER -->
                  FIELD-TAG              Immutable field
                | (FIELD-TAG)            Mutable field
              NONARGUMENT-FIELD-SPECIFIER -->
                  FIELD-TAG              Uninitialized field
                | (FIELD-TAG EXP)        Initialized with EXP's value
     This defines 'type/TYPE-NAME' to be a record type descriptor for
     the newly defined record type, 'TYPE-NAME-maker' to be a
     constructor for the new record type that accepts arguments for
     every field in the argument field specifier list, 'TYPE-NAME?' to
     be the disjoint type predicate for the new record type, accessors
     for each field tag FIELD-TAG by constructing an identifier
     'TYPE-NAME-FIELD-TAG', and modifiers for each argument field tag
     that was specified to be mutable as well as each nonargument field
     tag.  The name of the modifier for a field tag FIELD-TAG is
     constructed to be 'set-TYPE-NAME-FIELD-TAG!'.

     Note that Richard Kelsey's 'define-record-type' macro _does_
     concatenate & introduce new identifiers, unlike Jonathan Rees's.

     For example, a use of Richard Kelsey's 'define-record-type' macro

          (define-record-type pare
            (kar
             (kdr))
            (frob
             (mumble 5)))

     is equivalent to the following use of Jonathan Rees's macro

          (define-record-type pare type/pare
            (%pare-maker kar kdr mumble)
            pare?
            (kar pare-kar)
            (kdr pare-kdr set-pare-kdr!)
            (frob pare-frob set-pare-frob!)
            (mumble pare-mumble set-pare-mumble!))

          (define (pare-maker kar kdr)
            (%pare-maker kar kdr 5))

4.7.3 Record types
------------------

Along with two general record type definition facilities, there are
operations directly on the record type descriptors themselves, exported
by the 'record-types' structure.  (Record type descriptors are actually
records themselves.)

 -- procedure: make-record-type name field-tags -->
          record-type-descriptor
 -- procedure: record-type? object --> boolean
     'Make-record-type' makes a record type descriptor with the given
     name and field tags.  'Record-type?' is the disjoint type predicate
     for record types.

 -- procedure: record-type-name rtype-descriptor --> symbol
 -- procedure: record-type-field-names rtype-descriptor --> symbol-list
     Accessors for the two record type descriptor fields.

 -- procedure: record-constructor rtype-descriptor argument-field-tags
          --> constructor-procedure
 -- procedure: record-predicate rtype-descriptor --> predicate-procedure
 -- procedure: record-accessor rtype-descriptor field-tag -->
          accessor-procedure
 -- procedure: record-modifier rtype-descriptor field-tag -->
          modifier-procedure
     Constructors for the various procedures relating to record types.
     'Record-constructor' returns a procedure that accepts arguments for
     each field in ARGUMENT-FIELD-TAGS and constructs a record whose
     record type descriptor is RTYPE-DESCRIPTOR, initialized with its
     arguments.  'Record-predicate' returns a disjoint type predicate
     for records whose record type descriptor is RTYPE-DESCRIPTOR.
     'Record-accessor' and 'record-modifier' return accessors and
     modifiers for records whose record type descriptor is
     RTYPE-DESCRIPTOR for the given fields.

 -- procedure: define-record-discloser rtype-descriptor discloser -->
          unspecific
     Defines the method by which records of type RTYPE-DESCRIPTOR are
     disclosed (*note Writer::).  This is also exported by
     'define-record-types' and 'defrecord'.

 -- procedure: define-record-resumer rtype-descriptor resumer -->
          unspecified
     Sets RTYPE-DESCRIPTOR's record resumer to be RESUMER.  If RESUMER
     is '#t' (the default), records of this type require no particular
     reinitialization when found in dumped heap images (*note Suspending
     and resuming heap images::); if RESUMER is '#f', records of the
     type RTYPE-DESCRIPTOR may not be dumped in heap images; finally, if
     it is a procedure, and the heap image is resumed with the usual
     image resumer (*note Suspending and resuming heap images::), it is
     applied to each record whose record type descriptor is
     RTYPE-DESCRIPTOR after the run-time system has been initialized and
     before the argument to 'usual-resumer' is called.

   The 'records-internal' structure also exports these:

 -- record type: :record-type
     The record type of record types.

 -- procedure: disclose-record record --> disclosed
     This applies RECORD's record type descriptor's discloser procedure
     to RECORD to acquire a disclosed representation; *note Writer::.

   For expository purposes, the record type record type might have been
defined like so with Jonathan Rees's 'define-record-type' macro:

     (define-record-type record-type :record-type
       (make-record-type name field-names)
       record-type?
       (name record-type-name)
       (field-names record-type-field-names))

or like so with Richard Kelsey's 'define-record-type' macro:

     (define-record-type record-type
       (name field-names)
       ())

Of course, in reality, these definitions would have severe problems with
circularity of definition.

4.7.4 Low-level record manipulation
-----------------------------------

Internally, records are represented very similarly to vectors, and as
such have low-level operations on them similar to vectors, exported by
the 'records' structure.  Records usually reserve the slot at index 0
for their record type descriptor.

   *Warning:* The procedures described here can be very easily misused
to horribly break abstractions.  Use them very carefully, only in very
limited & extreme circumstances!

 -- procedure: make-record length init --> record
 -- procedure: record elt ... --> record
 -- procedure: record? object --> boolean
 -- procedure: record-length record --> integer
 -- procedure: record-ref record index --> value
 -- procedure: record-set! record index object --> unspecified
     Exact analogues of similarly named vector operation procedures.

 -- procedure: record-type record --> value
     This returns the record type descriptor of RECORD, i.e. the value
     of the slot at index 0 in RECORD.


File: scheme48.info,  Node: Suspending and resuming heap images,  Prev: Records,  Up: System facilities

4.8 Suspending and resuming heap images
=======================================

Scheme48's virtual machine operates by loading a heap image into memory
and calling the initialization procedure specified in the image dump.
Heap images can be produced in several different ways: programmatically
with 'write-image', using the command processor's facilities (*note
Image-building commands::), or with the static linker.  This section
describes only 'write-image' and the related system resumption &
initialization.

   Heap image dumps begin with a sequence of characters terminated by an
ASCII form-feed/page character (codepoint 12).  This content may be
anything; for example, it might be a Unix '#!' line that invokes
'scheme48vm' on the file, or it might be a silly message to whomever
reads the top of the heap image dump file.  (The command processor's
',dump' & ',build' commands (*note Image-building commands::) write a
blank line at the top; the static linker puts a message stating that the
image was built by the static linker.)

   'Write-image' is exported by the 'write-images' structure.

 -- procedure: write-image filename startup-proc message --> unspecified
     Writes a heap image whose startup procedure is STARTUP-PROC and
     that consists of every object accessible in some way from
     STARTUP-PROC.  MESSAGE is put at the start of the heap image file
     before the ASCII form-feed/page character.  When the image is
     resumed, STARTUP-PROC is passed a vector of program arguments, an
     input channel for standard input, an output channel for standard
     output, an output channel for standard error, and a vector of
     records to be resumed.  This is typically simplified by
     'usual-resumer' (see below).  On Unix, STARTUP-PROC must return an
     integer exit code; otherwise the program will crash and burn with a
     very low-level VM error message when STARTUP-PROC returns.

4.8.1 System initialization
---------------------------

When suspended heap images are resumed by the VM, the startup procedure
specified in the heap image is applied to five arguments: a vector of
command-line arguments (passed after the '-a' argument to the VM), an
input channel for standard input, an output channel for standard output,
an output channel for standard error, and a vector of records to be
resumed.  The startup procedure is responsible for performing any
initialization necessary -- including initializing the Scheme48 run-time
system -- as well as simply running the program.  Typically, this
procedure is not written manually: resumers are ordinarily created using
the "usual resumer" abstraction, exported from the structure
'usual-resumer'.

 -- procedure: usual-resumer startup-proc --> resumer-proc
     This returns a procedure that is suitable as a heap image resumer
     procedure.  When the heap image is resumed, it initializes the
     run-time system -- it resumes all the records, initializes the
     thread system, the dynamic state, the interrupt system, I/O system,
     &c. -- and applies STARTUP-PROC to a list (not a vector) of the
     command-line arguments.

   Some records may contain machine-, OS-, or other session-specific
data.  When suspended in heap images and later resumed, this data may be
invalidated, and it may be necessary to reinitialize this data upon
resumption of suspended heap images.  For this reason Scheme48 provides
"record resumers"; see 'define-record-resumer' from the 'record-types'
structure (*note Records::).

4.8.2 Manual system initialization
----------------------------------

If a programmer chooses not to use 'usual-resumer' -- which is _not_ a
very common thing to do --, he is responsible for manual initialization
of the run-time system, including the I/O system, resumption of records,
the thread system and the root thread scheduler, the interrupt system,
and the condition system.

   *Warning:* Manual initialization of the run-time system is a _very_
delicate operation.  Although one can potentially vastly decrease the
size of dumped heap images by doing it manually, (1) it is very
error-prone and difficult to do without exercising great care, which is
why the usual resumer facility exists.  Unless you _*really*_ know what
you are doing, you should just use the usual resumer.

   At the present, documentation of manual system initialization is
absent.  However, if the reader knows enough about what he is doing that
he desires to manually initialize the run-time system, he is probably
sufficiently familiar with it already to be able to find the necessary
information directly from Scheme48's source code and module
descriptions.

   ---------- Footnotes ----------

   (1) For example, the author of this manual, merely out of curiosity,
compared the sizes of two images: one that used the usual resumer and
printed each of its command-line arguments, and one that performed _no_
run-time system initialization -- which eliminated the run-time system
in the image, because it was untraceable from the resumer -- and wrote
directly to the standard output channel.  The difference was a factor of
about twenty.  However, also note that the difference is constant; the
run-time system happened to account for nineteen twentieths of the
larger image.


File: scheme48.info,  Node: Multithreading,  Next: Libraries,  Prev: System facilities,  Up: Top

5 Multithreading
****************

This chapter describes Scheme48's fully preëmptive and sophisticated
user-level thread system.  Scheme48 supports customized and nested
thread schedulers, user-designed synchronization mechanisms, optimistic
concurrency, useful thread synchronization libraries, a high-level event
algebra based on Reppy's Concurrent ML [Reppy 99], and common
pessimistic concurrency/mutual-exclusion-based thread synchronization
facilities.

* Menu:

* Basic thread operations::
* Optimistic concurrency::
* Higher-level synchronization::
* Concurrent ML::			High-level event synchronization
* Pessimistic concurrency::		Mutual exclusion/locking
* Custom thread synchronization::


File: scheme48.info,  Node: Basic thread operations,  Next: Optimistic concurrency,  Up: Multithreading

5.1 Basic thread operations
===========================

This section describes the 'threads' structure.

 -- procedure: spawn thunk [name] --> thread
     'Spawn' constructs a new thread and instructs the current thread
     scheduler to commence running the new thread.  NAME, if present, is
     used for debugging.  The new thread has a fresh dynamic environment
     (*note Fluid/dynamic bindings::).

   There are several miscellaneous facilities for thread operations.

 -- procedure: relinquish-timeslice --> unspecified
 -- procedure: sleep count --> unspecified
     'Relinquish-timeslice' relinquishes the remaining quantum that the
     current thread has to run; this allows the current scheduler run
     the next thread immediately.  'Sleep' suspends the current thread
     for COUNT milliseconds.

 -- procedure: terminate-current-thread --> (does not return)
     Terminates the current thread, running all 'dynamic-wind' exit
     points.  'Terminate-current-thread' obviously does not return.

   Threads may be represented and manipulated in first-class thread
descriptor objects.

 -- procedure: current-thread --> thread
 -- procedure: thread? object --> boolean
 -- procedure: thread-name thread --> value
 -- procedure: thread-uid thread --> unique-integer-id
     'Current-thread' returns the thread descriptor for the currently
     running thread.  'Thread?' is the thread descriptor disjoint type
     predicate.  'Thread-name' returns the name that was passed to
     'spawn' when spawning THREAD, or '#f' if no name was passed.
     'Thread-uid' returns a thread descriptor's unique integer
     identifier, assigned by the thread system.


File: scheme48.info,  Node: Optimistic concurrency,  Next: Higher-level synchronization,  Prev: Basic thread operations,  Up: Multithreading

5.2 Optimistic concurrency
==========================

Scheme48's fundamental thread synchronization mechanism is based on a
device often used in high-performance database systems: optimistic
concurrency.  The basic principle of optimistic concurrency is that,
rather than mutually excluding other threads from data involved in one
thread's transaction, a thread keeps a log of its transaction, not
actually modifying the data involved, only touching the log.  When the
thread is ready to commit its changes, it checks that all of the reads
from memory retained their integrity -- that is, all of the memory that
was read from during the transaction has remained the same, and is
consistent with what is there at the time of the commit.  If, and only
if, all of the reads remained valid, the logged writes are committed;
otherwise, the transaction has been invalidated.  While a thread is
transacting, any number of other threads may be also transacting on the
same resource.  All that matters is that the values each transaction
read are consistent with every write that was committed during the
transaction.  This synchronization mechanism allows for wait-free,
lockless systems that easily avoid confusing problems involving careful
sequences of readily deadlock-prone mutual exclusion.

   In the Scheme48 system, every thread has its own log of transactions,
called a "proposal".  There are variants of all data accessors &
modifiers that operate on the current thread's proposal, rather than
actual memory: after the initial read of a certain part of memory --
which _does_ perform a real read --, the value from that location in
memory is cached in the proposal, and thenceforth reads from that
location in memory will actually read the cache; modifications touch
only the proposal, until the proposal is committed.

   All of the names described in this section are exported by the
'proposals' structure.

5.2.1 High-level optimistic concurrency
---------------------------------------

There are several high-level operations that abstract the manipulation
of the current thread's proposal.

 -- procedure: call-ensuring-atomicity thunk --> values
 -- procedure: call-ensuring-atomicity! thunk --> unspecified
     These ensure that the operation of THUNK is atomic.  If there is
     already a current proposal in place, these are equivalent to
     calling THUNK.  If there is not a current proposal in place, these
     install a new proposal, call THUNK, and attempt to commit the new
     proposal.  If the commit succeeded, these return.  If it failed,
     these retry with a new proposal until they do succeed.
     'Call-ensuring-atomicity' returns the values that THUNK returned
     when the commit succeeded; 'call-ensuring-atomicity!' returns zero
     values -- it is intended for when THUNK is used for its effects
     only.

 -- procedure: call-atomically thunk --> values
 -- procedure: call-atomically! thunk --> unspecified
     These are like CALL-ENSURING-ATOMICITY and
     CALL-ENSURING-ATOMICITY!, respectively, except that they always
     install a new proposal (saving the old one and restoring it when
     they are done).

 -- syntax: ensure-atomicity body --> values
 -- syntax: ensure-atomicity! body --> unspecified
 -- syntax: atomically body --> values
 -- syntax: atomically! body --> unspecified
     These are syntactic sugar over 'call-ensuring-atomicity',
     'call-ensuring-atomicity!', 'call-atomically', and
     'call-atomically!', respectively.

   Use these high-level optimistic concurrency operations to make the
body atomic.  'Call-ensuring-atomicity' &c. simply ensure that the
transaction will be atomic, and may 'fuse' it with an enclosing atomic
transaction if there already is one, i.e. use the proposal for that
transaction already in place, creating one only if there is not already
one.  'Call-atomically' &c. are for what might be called 'subatomic'
transactions, which cannot be fused with other atomic transactions, and
for which there is always created a new proposal.

   However, code within 'call-ensuring-atomicity' &c. or
'call-atomically' &c. should _not_ explicitly commit the current
proposal; those operations above _automatically_ commit the current
proposal when the atomic transaction is completed.  (In the case of
'call-atomically' &c., this is when the procedure passed returns; in the
case of 'call-ensuring-atomicity' &c., this is when the outermost
enclosing atomic transaction completes, or the same as 'call-atomically'
if there was no enclosing atomic transaction.)  To explicitly commit the
current proposal -- for example, to perform some particular action if
the commit fails rather than just to repeatedly retry the transaction,
or to use operations from the customized thread synchronization (*note
Custom thread synchronization::) facilities that commit the current
proposal after their regular function, or the operations on condition
variables (*note Higher-level synchronization::) that operate on the
condition variable and then commit the current proposal --, one must use
the 'with-new-proposal' syntax as described below, not these operations.

5.2.2 Logging variants of Scheme procedures
-------------------------------------------

 -- procedure: provisional-car pair --> value
 -- procedure: provisional-cdr pair --> value
 -- procedure: provisional-set-car! pair value --> unspecified
 -- procedure: provisional-set-cdr! pair value --> unspecified
 -- procedure: provisional-cell-ref cell --> value
 -- procedure: provisional-cell-set! cell value --> unspecified
 -- procedure: provisional-vector-ref vector index --> value
 -- procedure: provisional-vector-set! vector index value -->
          unspecified
 -- procedure: provisional-string-ref string index --> char
 -- procedure: provisional-string-set! string index value -->
          unspecified
 -- procedure: provisional-byte-vector-ref byte-vector index --> char
 -- procedure: provisional-byte-vector-set! byte-vector index byte -->
          unspecified
 -- procedure: attempt-copy-bytes! from fstart to tstart count -->
          unspecified
     These are variants of most basic Scheme memory accessors &
     modifiers that log in the current proposal, rather than performing
     the actual memory access/modification.  All of these do perform the
     actual memory access/modification, however, if there is no current
     proposal in place when they are called.  'Attempt-copy-bytes!'
     copies a sequence of COUNT bytes from the byte vector or string
     FROM, starting at the index FSTART, to the byte vector or string
     TO, starting at the index TSTART.

5.2.3 Synchronized records
--------------------------

 -- syntax: define-synchronized-record-type
          (define-synchronized-record-type TAG TYPE-NAME
            (CONSTRUCTOR-NAME PARAMETER-FIELD-TAG ...)
            [(SYNC-FIELD-TAG ...)]
            PREDICATE-NAME
            (FIELD-TAG ACCESSOR-NAME [MODIFIER-NAME])
            ...)
     This is exactly like 'define-record-type' from the
     'define-record-types' structure, except that the accessors &
     modifiers for each field in SYNC-FIELD-TAG ... are defined to be
     provisional, i.e. to log in the current proposal.  If the list of
     synchronized fields is absent, all of the fields are synchronized,
     i.e. it is as if all were specified in that list.

   The 'proposals' structure also exports 'define-record-discloser'
(*note Records::).  Moreover, the 'define-sync-record-types' structure,
too, exports 'define-synchronized-record-type', though it does not
export 'define-record-discloser'.

5.2.4 Optimistic concurrency example
------------------------------------

Here is a basic example of using optimistic concurrency to ensure the
synchronization of memory.  We first present a simple mechanism for
counting integers by maintaining internal state, which is expressed
easily with closures:

     (define (make-counter value)
       (lambda ()
         (let ((v value))
           (set! value (+ v 1))
           v)))

   This has a problem: between obtaining the value of the closure's slot
for 'value' and updating that slot, another thread might be given
control and modify the counter, producing unpredictable results in
threads in the middle of working with the counter.  To remedy this, we
might add a mutual exclusion lock to counters to prevent threads from
simultaneously accessing the cell:

     (define (make-counter value)
       (let ((lock (make-lock)))
         (lambda ()
           (dynamic-wind
             (lambda () (obtain-lock lock))
             (lambda ()
               (let ((v value))
                 (set! value (+ v 1))
                 v))
             (lambda () (release-lock lock))))))

   This poses another problem, however.  Suppose we wish to write an
atomic '(step-counters! COUNTER ...)' procedure that increments each of
the supplied counters by one; supplying a counter N times should have
the effect of incrementing it by N.  The naïve definition of it is this:

     (define (step-counters! . counters)
       (for-each (lambda (counter) (counter))
                 counters))

   Obviously, though, this is not atomic, because each individual
counter is locked when it is used, but not the whole iteration across
them.  To work around this, we might use an obfuscated control structure
to allow nesting the locking of counters:

     (define (make-counter value)
       (let ((lock (make-lock)))
         (lambda args
           (dynamic-wind
             (lambda () (obtain-lock lock))
             (lambda ()
               (if (null? args)
                   (let ((v value))
                     (set! value (+ v 1))
                     v)
                   ((car args))))
             (lambda () (release-lock lock))))))

     (define (step-counters! . counters)
       (let loop ((cs counters))
         (if (null? cs)
             (for-each (lambda (counter) (counter))
                       counters)
             ((car cs) (lambda () (loop (cdr cs)))))))

   Aside from the obvious matter of the obfuscation of the control
structures used here, however, this has another problem: we cannot step
one counter multiple times atomically.  Though different locks can be
nested, nesting is very dangerous, because accidentally obtaining a lock
that is already obtained can cause deadlock, and there is no modular,
transparent way to avoid this in the general case.

   Instead, we can implement counters using optimistic concurrency to
synchronize the shared data.  The state of counters is kept explicitly
in a cell (*note Cells::), in order to use a provisional accessor &
modifier, as is necessary to make use of optimistic concurrency, and we
surround with 'call-ensuring-atomicity' any regions we wish to be
atomic:

     (define (make-counter initial)
       (let ((cell (make-cell initial)))
         (lambda ()
           (call-ensuring-atomicity
             (lambda ()
               (let ((value (provisional-cell-ref cell)))
                 (provisional-cell-set! cell (+ value 1))
                 value))))))

     (define (step-counters! . counters)
       (call-ensuring-atomicity!
         (lambda ()
           (for-each (lambda (counter) (counter))
                     counters))))

This approach has a number of advantages:

   * The original control structure is preserved, only with provisional
     operators for shared memory access that we explicitly wish to be
     synchronized and with 'call-ensuring-atomicity' wrapping the
     portions of code that we explicitly want to be atomic.

   * Composition of transactions is entirely transparent; it is
     accomplished automatically simply by 'call-ensuring-atomicity'.

   * Transactions can be nested arbitrarily deeply, and there is no
     problem of accidentally locking the same resource again at a deeper
     nesting level to induce deadlock.

   * No explicit mutual exclusion or blocking is necessary.  Threads
     proceed without heed to others, but do not actually write data to
     the shared memory until its validity is ensured.  There is no
     deadlock at all.

5.2.5 Low-level optimistic concurrency
--------------------------------------

Along with the higher-level operations described above, there are some
lower-level primitives for finer control over optimistic concurrency.

 -- procedure: make-proposal --> proposal
 -- procedure: current-proposal --> proposal
 -- procedure: set-current-proposal! proposal --> unspecified
 -- procedure: remove-current-proposal! --> unspecified
     'Make-proposal' creates a fresh proposal.  'Current-proposal'
     returns the current thread's proposal.  'Set-current-proposal!'
     sets the current thread's proposal to PROPOSAL.
     'Remove-current-proposal!' sets the current thread's proposal to
     '#f'.

 -- procedure: maybe-commit --> boolean
 -- procedure: invalidate-current-proposal! --> unspecified
     'Maybe-commit' checks that the current thread's proposal is still
     valid.  If it is, the proposal's writes are committed, and
     'maybe-commit' returns '#t'; if not, the current thread's proposal
     is set to '#f' and 'maybe-commit' returns '#f'.
     'Invalidate-current-proposal!' causes an inconsistency in the
     current proposal by caching a read and then directly writing to the
     place that read was from.

 -- syntax: with-new-proposal (lose) body --> values
     Convenience for repeating a transaction.  'With-new-proposal' saves
     the current proposal and will reinstates it when everything is
     finished.  After saving the current proposal, it binds LOSE to a
     nullary procedure that installs a fresh proposal and that evaluates
     BODY; it then calls LOSE.  Typically, the last thing, or close to
     last thing, that BODY will do is attempt to commit the current
     proposal, and, if that fails, call LOSE to retry.
     'With-new-proposal' expands to a form that returns the values that
     BODY returns.

     This 'retry-at-most' example tries running the transaction of
     THUNK, and, if it fails to commit, retries at most N times.  If the
     transaction is successfully committed before N repeated attempts,
     it returns true; otherwise, it returns false.

          (define (retry-at-most n thunk)
            (with-new-proposal (lose)
              (thunk)
              (cond ((maybe-commit) #t)
                    ((zero? n)      #f)
                    (else (set! n (- n 1))
                          (lose)))))


File: scheme48.info,  Node: Higher-level synchronization,  Next: Concurrent ML,  Prev: Optimistic concurrency,  Up: Multithreading

5.3 Higher-level synchronization
================================

This section details the various higher-level thread synchronization
devices that Scheme48 provides.

5.3.1 Condition variables
-------------------------

"Condition variables" are multiple-assignment cells on which readers
block.  Threads may wait on condition variables; when some other thread
assigns a condition variable, all threads waiting on it are revived.
The 'condvars' structure exports all of these condition-variable-related
names.

   In many concurrency systems, condition variables are operated in
conjunction with mutual exclusion locks.  On the other hand, in
Scheme48, they are used in conjunction with its optimistic concurrency
devices.

 -- procedure: make-condvar [id] --> condvar
 -- procedure: condvar? object --> boolean
     Condition variable constructor & disjoint type predicate.  ID is
     used purely for debugging.

 -- procedure: maybe-commit-and-wait-for-condvar condvar --> boolean
 -- procedure: maybe-commit-and-set-condvar! condvar value --> boolean
     'Maybe-commit-and-wait-for-condvar' attempts to commit the current
     proposal.  If the commit succeeded, the current thread is blocked
     on CONDVAR, and when the current thread is woken up,
     'maybe-commit-and-wait-for-condvar' returns '#t'.  If the commit
     did not succeed, 'maybe-commit-and-wait-for-condvar' immediately
     returns '#f'.  'Maybe-commit-and-set-condvar!' attempts to commit
     the current proposal as well.  If it succeeds, it is noted that
     CONDVAR has a value, CONDVAR's value is set to be VALUE, and all
     threads waiting on CONDVAR are woken up.

     *Note:* Do not use these in atomic transactions as delimited by
     'call-ensuring-atomicity' &c.; see the note in *note Optimistic
     concurrency:: on this matter for details.

 -- procedure: condvar-has-value? condvar --> boolean
 -- procedure: condvar-value condvar --> value
     'Condvar-has-value?' tells whether or not CONDVAR has been
     assigned.  If it has been assigned, 'condvar-value' accesses the
     value to which it was assigned.

 -- procedure: set-condvar-has-value?! condvar boolean --> unspecified
 -- procedure: set-condvar-value! condvar value --> unspecified
     'Set-condvar-has-value?!' is used to tell whether or not CONDVAR is
     assigned.  'Set-condvar-value!' sets CONDVAR's value.

     *Note:* 'Set-condvar-has-value?!' should be used only with a second
     argument of '#f'.  'Set-condvar-value!' is a very dangerous
     routine, and 'maybe-commit-and-set-condvar!' is what one should
     almost always use, except if one wishes to clean up after
     unassigning a condition variable.

5.3.2 Placeholders
------------------

"Placeholders" are similar to condition variables, except that they may
be assigned only once; they are in general a much simpler mechanism for
throw-away temporary synchronization devices.  They are provided by the
'placeholders' structure.

 -- procedure: make-placeholder [id] --> placeholder
 -- procedure: placeholder? object --> boolean
     Placeholder constructor & disjoint type predicate.  ID is used only
     for debugging purposes when printing placeholders.

 -- procedure: placeholder-value placeholder --> value
 -- procedure: placeholder-set! placeholder value --> unspecified
     'Placeholder-value' blocks until PLACEHOLDER is assigned, at which
     point it returns the value assigned.  'Placeholder-set!' assigns
     PLACEHOLDER's value to VALUE, awakening all threads waiting for
     PLACEHOLDER.  It is an error to assign a placeholder with
     'placeholder-set!' that has already been assigned.

5.3.3 Value pipes
-----------------

"Value pipes" are asynchronous communication pipes between threads.  The
'value-pipes' structure exports these value pipe operations.

 -- procedure: make-pipe [size [id]] --> value-pipe
 -- procedure: pipe? object --> boolean
     'Make-pipe' is the value pipe constructor.  SIZE is a limit on the
     number of elements the pipe can hold at one time.  ID is used for
     debugging purposes only in printing pipes.  'Pipe?' is the disjoint
     type predicate for value pipes.

 -- procedure: empty-pipe? pipe --> boolean
 -- procedure: empty-pipe! pipe --> unspecified
     'Empty-pipe?' returns '#t' if PIPE has no elements in it and '#f'
     if not.  'Empty-pipe!' removes all elements from 'pipe'.

 -- procedure: pipe-read! pipe --> value
 -- procedure: pipe-maybe-read! pipe --> value or '#f'
 -- procedure: pipe-maybe-read?! pipe --> [boolean value]
     'Pipe-read!' reads a value from PIPE, removing it from the queue.
     It blocks if there are no elements available in the queue.
     'Pipe-maybe-read!' attempts to read & return a single value from
     PIPE; if no elements are available in its queue, it instead returns
     '#f'.  'Pipe-maybe-read?!' does similarly, but it returns two
     values: a boolean, signifying whether or not a value was read; and
     the value, or '#f' if no value was read.  'Pipe-maybe-read?!' is
     useful when PIPE may contain the value '#f'.

 -- procedure: pipe-write! pipe value --> unspecified
 -- procedure: pipe-push! pipe value --> unspecified
 -- procedure: pipe-maybe-write! pipe value --> boolean
     'Pipe-write!' attempts to add VALUE to PIPE's queue.  If PIPE's
     maximum size, as passed to 'make-pipe' when constructing the pipe,
     is either '#f' or greater than the number of elements in PIPE's
     queue, 'pipe-write!' will not block; otherwise it will block until
     a space has been made available in the pipe's queue by another
     thread reading from it.  'Pipe-push!' does similarly, but, in the
     case where the pipe is full, it pushes the first element to be read
     out of the pipe.  'Pipe-maybe-write!' is also similar to
     'pipe-write!', but it returns '#t' if the pipe was not full, and it
     _immediately_ returns '#f' if the pipe was full.


File: scheme48.info,  Node: Concurrent ML,  Next: Pessimistic concurrency,  Prev: Higher-level synchronization,  Up: Multithreading

5.4 Concurrent ML
=================

Scheme48 provides a high-level event synchronization facility based on
on Reppy's "Concurrent ML" [Reppy 99].  The primary object in CML is the
"rendezvous"(1), which represents a point of process synchronization.  A
rich library for manipulating rendezvous and several useful, high-level
synchronization abstractions are built atop rendezvous.

* Menu:


* Rendezvous concepts::
* Rendezvous base combinators::
* Rendezvous communication channels::
* Rendezvous-synchronized cells::
* Concurrent ML to Scheme correspondence::

   ---------- Footnotes ----------

   (1) In the original CML, these were called "events", but that term
was deemed too overloaded and confusing when Scheme48's library was
developed.


File: scheme48.info,  Node: Rendezvous concepts,  Next: Rendezvous base combinators,  Up: Concurrent ML

5.4.1 Rendezvous concepts
-------------------------

When access to a resource must be synchronized between multiple
processes, for example to transmit information from one process to
another over some sort of communication channel, the resource provides a
"rendezvous" to accomplish this, which represents a potential point of
synchronization between processes.  The use of rendezvous occurs in two
stages: "synchronization" and "enablement".  Note that creation of
rendezvous is an unrelated matter, and it does not (or should not)
itself result in any communication or synchronization between processes.

   When a process requires an external resource for which it has a
rendezvous, it "synchronizes" that rendezvous.  This first polls whether
the resource is immediately available; if so, the rendezvous is already
"enabled", and a value from the resource is immediately produced from
the synchronization.  Otherwise, the synchronization of the rendezvous
is recorded somehow externally, and the process is blocked until the
rendezvous is enabled by an external entity, usually one that made the
resource available.  Rendezvous may be reüsed arbitrarily many times;
the value produced by an enabled, synchronized rendezvous is not cached.
Note, however, that the construction of a rendezvous does not (or should
not) have destructive effect, such as sending a message to a remote
server or locking a mutex; the only destructive effects should be
incurred at synchronization or enablement time.  For effecting
initialization prior to the synchronization of a rendezvous, see below
on "delayed rendezvous".

   Rendezvous may consist of multiple rendezvous choices, any of which
may be taken when enabled but only one of which actually is.  If, when a
composite rendezvous is initially synchronized, several components are
immediately enabled, each one has a particular numeric priority which is
used to choose among them.  If several are tied for the highest
priority, a random one is chosen.  If none is enabled when the choice is
synchronized, however, the synchronizer process is suspended until the
first one is enabled and revives the process.  When this happens, any or
all of the other rendezvous components may receive a negative
acknowledgement; see below on "delayed rendezvous with negative
acknowledgement".

   A rendezvous may also be a rendezvous "wrapped" with a procedure,
which means that, when the internal rendezvous becomes enabled, the
wrapper one also becomes enabled, and the value it produces is the
result of applying its procedure to the value that the internal
rendezvous produced.  This allows the easy composition of complex
rendezvous from simpler ones, and it also provides a simple mechanism
for performing different actions following the enablement of different
rendezvous, rather than conflating the results of several possible
rendezvous choices into one value and operating on that (though this,
too, can be a useful operation).

5.4.2 Delayed rendezvous
------------------------

A rendezvous may be "delayed", which means that its synchronization
requires some processing that could not or would not be reasonable to
perform at its construction.  It consists of a nullary procedure to
generate the actual rendezvous to synchronize when the delayed
rendezvous is itself synchronized.

   For example, a rendezvous for generating unique identifiers, by
sending a request over a network to some server and waiting for a
response, could not be constructed by waiting for a response from the
server, because that may block, which should not occur until
synchronization.  It also could not be constructed by first sending a
request to the server at all, because that would have a destructive
effect, which is not meant to happen when creating a rendezvous, only
when synchronizing or enabling one.

   Instead, the unique identifier rendezvous would be implemented as a
delayed rendezvous that, when synchronized, would send a request to the
server and generate a rendezvous for the actual synchronization that
would become enabled on receiving the server's response.

5.4.2.1 Negative acknowledgements
.................................

Delayed rendezvous may also receive negative acknowledgements.  Rather
than a simple nullary procedure being used to generate the actual
rendezvous for synchronization, the procedure is unary, and it is passed
a "negative acknowledgement rendezvous", or "nack" for short.  This nack
is enabled if the actual rendezvous was not chosen among a composite
group of rendezvous being synchronized.  This allows not only delaying
initialization of rendezvous until necessary but also aborting or
rescinding initialized transactions if their rendezvous are unchosen and
therefore unused.

   For example, a complex database query might be the object of some
rendezvous, but it is pointless to continue constructing the result if
that rendezvous is not chosen.  A nack can be used to prematurely abort
the query to the database if another rendezvous was chosen in the stead
of that for the database query.


File: scheme48.info,  Node: Rendezvous base combinators,  Next: Rendezvous communication channels,  Prev: Rendezvous concepts,  Up: Concurrent ML

5.4.3 Rendezvous combinators
----------------------------

The 'rendezvous' structure exports several basic rendezvous combinators.

 -- Constant: never-rv --> rendezvous
     A rendezvous that is never enabled.  If synchronized, this will
     block the synchronizing thread indefinitely.

 -- procedure: always-rv value --> rendezvous
     Returns a rendezvous that is always enabled with the given value.
     This rendezvous will never block the synchronizing thread.

 -- procedure: guard rv-generator --> rendezvous
 -- procedure: with-nack rv-generator --> rendezvous
     'Guard' returns a delayed rendezvous, generated by the given
     procedure RV-GENERATOR, which is passed zero arguments whenever the
     resultant rendezvous is synchronized.  'With-nack' returns a
     delayed rendezvous for which a negative acknowledgement rendezvous
     is constructed.  If the resultant rendezvous is synchronized as a
     part of a composite rendezvous, the procedure 'rv-generator' is
     passed a nack for the synchronization, and it returns the
     rendezvous to actually synchronize.  If the delayed rendezvous was
     synchronized as part of a composite group of rendezvous, and
     another rendezvous among that group is enabled and chosen first,
     the nack is enabled.

 -- procedure: choose rendezvous ... --> composite-rendezvous
     Returns a rendezvous that, when synchronized, synchronizes all of
     the given components, and chooses only the first one to become
     enabled, or the highest priority one if there are any that are
     already enabled.  If any of the rendezvous that were not chosen
     when the composite became enabled were delayed rendezvous with
     nacks, their nacks are enabled.

 -- procedure: wrap rendezvous procedure --> rendezvous
     Returns a rendezvous equivalent to RENDEZVOUS but wrapped with
     PROCEDURE, so that, when the resultant rendezvous is synchronized,
     RENDEZVOUS is transitively synchronized, and when RENDEZVOUS is
     enabled, the resultant rendezvous is also enabled, with the value
     that PROCEDURE returns when passed the value produced by
     RENDEZVOUS.

          (sync (wrap (always-rv 4)
                      (lambda (x) (* x x))))      --> 16

 -- procedure: sync rendezvous --> value (may block)
 -- procedure: select rendezvous ... --> value (may block)
     'Sync' and 'select' synchronize rendezvous.  'Sync' synchronizes a
     single one; 'select' synchronizes any from the given set of them.
     'Select' is equivalent to '(sync (apply choose RENDEZVOUS ...))',
     but it may be implemented more efficiently.

5.4.3.1 Timing rendezvous
.........................

The 'rendezvous-time' structure exports two constructors for rendezvous
that become enabled only at a specific time or after a delay in time.

 -- procedure: at-real-time-rv milliseconds --> rendezvous
 -- procedure: after-time-rv milliseconds --> rendezvous
     'At-real-time-rv' returns a rendezvous that becomes enabled at the
     time MILLISECONDS relative to the start of the Scheme program.
     'After-time-rv' returns a rendezvous that becomes enabled at least
     MILLISECONDS after synchronization (_not_ construction).


File: scheme48.info,  Node: Rendezvous communication channels,  Next: Rendezvous-synchronized cells,  Prev: Rendezvous base combinators,  Up: Concurrent ML

5.4.4 Rendezvous communication channels
---------------------------------------

5.4.4.1 Synchronous channels
............................

The 'rendezvous-channels' structure provides a facility for "synchronous
channels": channels for communication between threads such that any
receiver blocks until another thread sends a message, or any sender
blocks until another thread receives the sent message.  In CML,
synchronous channels are also called merely 'channels.'

 -- procedure: make-channel --> channel
 -- procedure: channel? object --> boolean
     'Make-channel' creates and returns a new channel.  'Channel?' is
     the disjoint type predicate for channels.

 -- procedure: send-rv channel message --> rendezvous
 -- procedure: send channel message --> unspecified (may block)
     'Send-rv' returns a rendezvous that, when synchronized, becomes
     enabled when a reception rendezvous for CHANNEL is synchronized, at
     which point that reception rendezvous is enabled with a value of
     MESSAGE.  When enabled, the rendezvous returned by 'send-rv'
     produces an unspecified value.  'Send' is like 'send-rv', but it
     has the effect of immediately synchronizing the rendezvous, so it
     therefore may block, and it does not return a rendezvous; '(send
     CHANNEL MESSAGE)' is equivalent to '(sync (send-rv CHANNEL
     MESSAGE))'.

 -- procedure: receive-rv channel --> rendezvous
 -- procedure: receive channel --> value (may block)
     'Receive-rv' returns a rendezvous that, when synchronized, and when
     a sender rendezvous for CHANNEL with some message is synchronized,
     becomes enabled with that message, at which point the sender
     rendezvous is enabled with an unspecified value.  'Receive' is like
     'receive-rv', but it has the effect of immediately synchronizing
     the reception rendezvous, so it therefore may block, and it does
     not return the rendezvous but rather the message that was sent;
     '(receive CHANNEL)' is equivalent to '(sync (receive-rv CHANNEL))'.

5.4.4.2 Asynchronous channels
.............................

The 'rendezvous-async-channels' provides an "asynchronous channel"(1)
facility.  Like synchronous channels, any attempts to read from an
asynchronous channel will block if there are no messages waiting to be
read.  Unlike synchronous channels, however, sending a message will
never block.  Instead, a queue of messages or a queue of recipients is
maintained: if a message is sent and there is a waiting recipient, the
message is delivered to that recipient; otherwise it is added to the
queue of messages.  If a thread attempts to receive a message from an
asynchronous channel and there is a pending message, it receives that
message; otherwise it adds itself to the list of waiting recipients and
then blocks.

   *Note:* Operations on synchronous channels from the structure
'rendezvous-channels' do not work on asynchronous channels.

 -- procedure: make-async-channel --> async-channel
 -- procedure: async-channel? obj --> boolean
     'Make-async-channel' creates and returns an asynchronous channel.
     'Async-channel?' is the disjoint type predicate for asynchronous
     channels.

 -- procedure: receive-async-rv channel --> rendezvous
 -- procedure: receive-async channel --> value (may block)
     'Receive-async-rv' returns a rendezvous that, when synchronized,
     becomes enabled when a message is available in CHANNEL's queue of
     messages.  'Receive-async' has the effect of immediately
     synchronizing such a rendezvous and, when the rendezvous becomes
     enabled, returning the value itself, rather than the rendezvous;
     '(receive-async CHANNEL)' is equivalent to '(sync (receive-async-rv
     CHANNEL))'.

 -- procedure: send-async channel message --> unspecified
     Sends a message to the asynchronous channel CHANNEL.  Unlike the
     synchronous channel 'send' operation, this procedure never blocks
     arbitrarily long.(2)  There is, therefore, no need for a
     'send-async-rv' like the 'send-rv' for synchronous channels.  If
     there is a waiting message recipient, the message is delivered to
     that recipient; otherwise, it is added to the channel's message
     queue.

   ---------- Footnotes ----------

   (1) Known as "mailboxes" in Reppy's original CML.

   (2) However, asynchronous channels are implemented by a thread that
manages two synchronous channels (one for sends & one for receives), so
this may block briefly if the thread is busy receiving other send or
receive requests.


File: scheme48.info,  Node: Rendezvous-synchronized cells,  Next: Concurrent ML to Scheme correspondence,  Prev: Rendezvous communication channels,  Up: Concurrent ML

5.4.5 Rendezvous-synchronized cells
-----------------------------------

5.4.5.1 Placeholders: single-assignment cells
.............................................

"Placeholders"(1) are single-assignment cells on which readers block
until they are assigned.

   *Note:* These placeholders are disjoint from and incompatible with
the placeholder mechanism provided in the 'placeholders' structure, and
attempts to apply operations on one to values of the other are errors.

 -- procedure: make-placeholder [id] --> empty placeholder
 -- procedure: placeholder? object --> boolean
     'Make-placeholder' creates and returns a new, empty placeholder.
     ID is used only for debugging purposes; it is included in the
     printed representation of the placeholder.  'Placeholder?' is the
     disjoint type predicate for placeholders.

 -- procedure: placeholder-value-rv placeholder --> rendezvous
 -- procedure: placeholder-value placeholder --> value (may block)
     'Placeholder-value-rv' returns a rendezvous that, when
     synchronized, becomes enabled when PLACEHOLDER has a value, with
     that value.  'Placeholder-value' has the effect of immediately
     synchronizing such a rendezvous, and it returns the value directly,
     but possibly after blocking.

 -- procedure: placeholder-set! placeholder value --> unspecified
     Sets PLACEHOLDER's value to be VALUE, and enables all rendezvous
     for PLACEHOLDER's value with that value.  It is an error if
     PLACEHOLDER has already been assigned.

5.4.5.2 Jars: multiple-assignment cells
.......................................

"Jars"(2) are multiple-assignment cells on which readers block.  Reading
from a full jar has the effect of emptying it, enabling the possibility
of subsequent assignment, unlike placeholders; and jars may be assigned
multiple times, but, like placeholders, only jars that are empty may be
assigned.

 -- procedure: make-jar [id] --> empty jar
 -- procedure: jar? object --> boolean
     'Make-jar' creates and returns a new, empty jar.  ID is used only
     for debugging purposes; it is included in the printed
     representation of the jar.  'Jar?' is the disjoint type predicate
     for jars.

 -- procedure: jar-take-rv jar --> rendezvous
 -- procedure: jar-take jar --> value (may block)
     'Jar-take-rv' returns a rendezvous that, when synchronized, becomes
     enabled when JAR has a value, which is what value the rendezvous
     becomes enabled with; when that rendezvous is enabled, it also
     removes the value from JAR, putting the jar into an empty state.
     'Jar-take' has the effect of synchronizing such a rendezvous, may
     block because of that, and returns the value of the jar directly,
     not a rendezvous.

 -- procedure: jar-put! jar value --> unspecified
     'Jar-put!' puts VALUE into the empty jar JAR.  If any taker
     rendezvous are waiting, the first is enabled with the value, and
     the jar is returned to its empty state; otherwise, the jar is put
     in the full state.  'Jar-put!' is an error if applied to a full
     jar.

   ---------- Footnotes ----------

   (1) Called "I-variables" in Reppy's CML, and "I-structures" in ID-90.

   (2) Termed "M-variables" in Reppy's CML.


File: scheme48.info,  Node: Concurrent ML to Scheme correspondence,  Prev: Rendezvous-synchronized cells,  Up: Concurrent ML

5.4.6 Concurrent ML to Scheme correspondence
--------------------------------------------

CML name              Scheme name
structure 'CML'       structure 'threads'
'version'             (no equivalent)
'banner'              (no equivalent)
'spawnc'              (no equivalent; use 'spawn' and 'lambda')
'spawn'               'spawn'
'yield'               'relinquish-timeslice'
'exit'                'terminate-current-thread'
'getTid'              'current-thread'
'sameTid'             'eq?' (R5RS)
'tidToString'         (no equivalent; use the writer)
                      structure 'threads-internal'
'hashTid'             'thread-uid'
                      structure 'rendezvous'
'wrap'                'wrap'
'guard'               'guard'
'withNack'            'with-nack'
'choose'              'choose'
'sync'                'sync'
'select'              'select'
'never'               'never-rv'
'alwaysEvt'           'always-rv'
'joinEvt'             (no equivalent)
                      structure 'rendezvous-channels'
'channel'             'make-channel'
'sameChannel'         'eq?' (R5RS)
'send'                'send'
'recv'                'receive'
'sendEvt'             'send-rv'
'recvEvt'             'receive-rv'
'sendPoll'            (no equivalent)
'recvPoll'            (no equivalent)
                      structure 'rendezvous-time'
'timeOutEvt'          'after-time-rv'
'atTimeEvt'           'at-real-time-rv'
structure 'SyncVar'   structure 'rendezvous-placeholders'
exception 'Put'       (no equivalent)
'iVar'                'make-placeholder'
'iPut'                'placeholder-set!'
'iGet'                'placeholder-value'
'iGetEvt'             'placeholder-value-rv'
'iGetPoll'            (no equivalent)
'sameIVar'            'eq?' (R5RS)
                      structure 'jars'
'mVar'                'make-jar'
'mVarInit'            (no equivalent)
'mPut'                'jar-put!'
'mTake'               'jar-take'
'mTakeEvt'            'jar-take-rv'
'mGet'                (no equivalent)
'mGetEvt'             (no equivalent)
'mTakePoll'           (no equivalent)
'mGetPoll'            (no equivalent)
'mSwap'               (no equivalent)
'mSwapEvt'            (no equivalent)
'sameMVar'            'eq?' (R5RS)
structure 'Mailbox'   structure 'rendezvous-async-channels'
'mailbox'             'make-async-channel'
'sameMailbox'         'eq?' (R5RS)
'send'                'send-async'
'recv'                'receive-async'
'recvEvt'             'receive-async-rv'
'recvPoll'            (no equivalent)


File: scheme48.info,  Node: Pessimistic concurrency,  Next: Custom thread synchronization,  Prev: Concurrent ML,  Up: Multithreading

5.5 Pessimistic concurrency
===========================

While Scheme48's primitive thread synchronization mechanisms revolve
around optimistic concurrency, Scheme48 still provides the more
well-known mechanism of pessimistic concurrency, or mutual exclusion,
with locks.  Note that Scheme48's pessimistic concurrency facilities are
discouraged, and very little of the system uses them (at the time this
documentation was written, none of the system uses locks), and the
pessimistic concurrency libraries are limited to just locks; condition
variables are integrated only with optimistic concurrency.  Except for
inherent applications of pessimistic concurrency, it is usually better
to use optimistic concurrency in Scheme48.

   These names are exported by the 'locks' structure.

 -- procedure: make-lock --> lock
 -- procedure: lock? --> boolean
 -- procedure: obtain-lock lock --> unspecified
 -- procedure: maybe-obtain-lock lock --> boolean
 -- procedure: release-lock lock --> unspecified
     'Make-lock' creates a new lock in the 'released' lock state.
     'Lock?' is the disjoint type predicate for locks.  'Obtain-lock'
     atomically checks to see if LOCK is in the 'released' state: if it
     is, LOCK is put into the 'obtained' lock state; otherwise,
     'obtain-lock' waits until LOCK is ready to be obtained, at which
     point it is put into the 'obtained' lock state.
     'Maybe-obtain-lock' atomically checks to see if LOCK is in the
     'released' state: if it is, LOCK is put into the 'obtained' lock
     state, and 'maybe-obtain-lock' returns '#t'; if it is in the
     'obtained' state, 'maybe-obtain-lock' immediately returns '#f'.
     'Release-lock' sets LOCK's state to be 'released,' letting the next
     thread waiting to obtain it do so.


File: scheme48.info,  Node: Custom thread synchronization,  Prev: Pessimistic concurrency,  Up: Multithreading

5.6 Custom thread synchronization
=================================

Along with several useful thread synchronization abstraction facilities
built-in to Scheme48, there is also a simple and lower-level mechanism
for suspending & resuming threads.  The following bindings are exported
from the 'threads-internal' structure.

   Threads have a field for a cell (*note Cells::) that is used when the
thread is suspended.  When it is ready to run, it is simply '#f'.
Suspending a thread involves setting its cell to a cell accessible
outside, so the thread can later be awoken.  When the thread is awoken,
its cell field and the contents of the cell are both set to '#f'.
Often, objects involved in the synchronization of threads will have a
queue (*note Queues::) of thread cells.  There are two specialized
operations on thread cell queues that simplify filtering out cells of
threads that have already been awoken.

 -- procedure: maybe-commit-and-block cell --> boolean
 -- procedure: maybe-commit-and-block-on-queue --> boolean
     These attempt to commit the current proposal.  If the commit fails,
     they immediately return '#f'.  Otherwise, they suspend the current
     thread.  'Maybe-commit-and-block' first sets the current thread's
     cell to CELL, which should contain the current thread.
     'Maybe-commit-and-block-on-queue' adds a cell containing the
     current thread to QUEUE first.  When the current thread is finally
     resumed, these return '#t'.

 -- procedure: maybe-commit-and-make-ready thread-or-queue --> boolean
     Attempts to commit the current proposal.  If the commit fails, this
     returns '#f'.  Otherwise, 'maybe-commit-and-make-ready' awakens the
     specified thread[s] by clearing the thread/each thread's cell and
     sending a message to the relevant scheduler[s] and returns '#t'.
     If THREAD-OR-QUEUE is a thread, it simply awakens that; if it is a
     queue, it empties the queue and awakens each thread in it.

 -- procedure: maybe-dequeue-thread! thread-cell-queue --> thread or
          boolean
 -- procedure: thread-queue-empty? thread-cell-queue --> boolean
     'Maybe-dequeue-thread!' returns the next thread cell's contents in
     the queue of thread cells THREAD-CELL-QUEUE.  It removes cells that
     have been emptied, i.e. whose threads have already been awoken.
     'Thread-queue-empty?' returns '#t' if there are no cells in
     THREAD-CELL-QUEUE that contain threads, i.e. threads that are still
     suspended.  It too removes cells that have been emptied.

   For example, the definition of placeholders (*note Higher-level
synchronization::) is presented here.  Placeholders contain two fields:
the cached value (set when the placeholder is set) & a queue of threads
waiting (set to '#f' when the placeholder is assigned).

     (define-synchronized-record-type placeholder :placeholder
       (really-make-placeholder queue)
       (value queue)                         ; synchronized fields
       placeholder?
       (queue placeholder-queue set-placeholder-queue!)
       (value placeholder-real-value set-placeholder-value!))

     (define (make-placeholder)
       (really-make-placeholder (make-queue)))

     (define (placeholder-value placeholder)
       ;; Set up a new proposal for the transaction.
       (with-new-proposal (lose)
         (cond ((placeholder-queue placeholder)
                ;; There's a queue of waiters.  Attempt to commit the
                ;; proposal and block.  We'll be added to the queue if the
                ;; commit succeeds; if it fails, retry.
                => (lambda (queue)
                     (or (maybe-commit-and-block-on-queue queue)
                         (lose))))))
       ;; Once our thread has been awoken, the placeholder will be set.
       (placeholder-real-value placeholder))

     (define (placeholder-set! placeholder value)
       ;; Set up a new proposal for the transaction.
       (with-new-proposal (lose)
         (cond ((placeholder-queue placeholder)
                => (lambda (queue)
                     ;; Clear the queue, set the value field.
                     (set-placeholder-queue! placeholder #f)
                     (set-placeholder-value! placeholder value)
                     ;; Attempt to commit our changes and awaken all of the
                     ;; waiting threads.  If the commit fails, retry.
                     (if (not (maybe-commit-and-make-ready queue))
                         (lose))))
               (else
                ;; Someone assigned it first.  Since placeholders are
                ;; single-assignment cells, this is an error.
                (error "placeholder is already assigned"
                       placeholder
                       (placeholder-real-value placeholder))))))


File: scheme48.info,  Node: Libraries,  Next: C interface,  Prev: Multithreading,  Up: Top

6 Libraries
***********

This chapter details a number of useful libraries built-in to Scheme48.

* Menu:

* Boxed bitwise-integer masks::
* Enumerated/finite types and sets::
* Macros for writing loops::
* Library data structures::
* I/O extensions::
* TCP & UDP sockets::
* Common-Lisp-style formatting::
* Library utilities::


File: scheme48.info,  Node: Boxed bitwise-integer masks,  Next: Enumerated/finite types and sets,  Up: Libraries

6.1 Boxed bitwise-integer masks
===============================

Scheme48 provides a facility for generalized boxed bitwise-integer
masks.  Masks represent sets of elements.  An element is any arbitrary
object that represents an index into a bit mask; mask types are
parameterized by an isomorphism between elements and their integer
indices.  Usual abstract set operations are available on masks.  The
mask facility is divided into two parts: the 'mask-types' structure,
which provides the operations on the generalized mask type descriptors;
and the 'masks' structure, for the operations on masks themselves.

6.1.1 Mask types
----------------

 -- procedure: make-mask-type name elt? index->elt elt->index size -->
          mask-type
 -- procedure: mask-type? object --> boolean
 -- procedure: mask? object --> boolean
     'Make-mask-type' constructs a mask type with the given name.
     Elements of this mask type must satisfy the predicate ELT?.
     INTEGER->ELT is a unary procedure that maps bit mask indices to
     possible set elements; ELT->INTEGER maps possible set elements to
     bit mask indices.  SIZE is the number of possible elements of masks
     of the new type, i.e. the number of bits needed to represent the
     internal bit mask.  'Mask?' is the disjoint type predicate for mask
     objects.

 -- procedure: mask-type mask --> mask-type
 -- procedure: mask-has-type? mask type --> boolean
     'Mask-type' returns MASK's type.  'Mask-has-type?' returns '#t' if
     MASK's type is the mask type TYPE or '#f' if not.

   The 'mask-types' structure, not the 'masks' structure, exports
'mask?' and 'mask-has-type?': it is expected that programmers who
implement mask types will define type predicates for masks of their type
based on 'mask?' and 'mask-has-type?', along with constructors &c. for
their masks.

 -- procedure: integer->mask type integer --> mask
 -- procedure: list->mask type elts --> mask
     'Integer->mask' returns a mask of type TYPE that contains all the
     possible elements E of the type TYPE such that the bit at E's index
     is set.  'List->mask' returns a mask whose type is TYPE containing
     all of the elements in the list ELTS.

6.1.2 Masks
-----------

 -- procedure: mask->integer mask --> integer
 -- procedure: mask->list mask --> element-list
     'Mask->integer' returns the integer bit set that MASK uses to
     represent the element set.  'Mask->list' returns a list of all the
     elements that MASK contains.

 -- procedure: mask-member? mask elt --> boolean
 -- procedure: mask-set mask elt ... --> mask
 -- procedure: mask-clear mask elt ... --> mask
     'Mask-member?' returns true if ELT is a member of the mask MASK, or
     '#f' if not.  'Mask-set' returns a mask with all the elements in
     MASK as well as each ELT ....  'Mask-clear' returns a mask with all
     the elements in MASK but with none of ELT ....

 -- procedure: mask-union mask_{1} mask_{2} ... --> mask
 -- procedure: mask-intersection mask_{1} mask_{2} ... --> mask
 -- procedure: mask-subtract mask--_{a} mask--_{b} --> mask
 -- procedure: mask-negate mask --> mask
     Set operations on masks.  'Mask-union' returns a mask containing
     every element that is a member of any one of its arguments.
     'Mask-intersection' returns a mask containing every element that is
     a member of every one of its arguments.  'Mask-subtract' returns a
     mask of every element that is in MASK-_{A} but not also in
     MASK-_{B}.  'Mask-negate' returns a mask whose members are every
     possible element of MASK's type that is not in MASK.


File: scheme48.info,  Node: Enumerated/finite types and sets,  Next: Macros for writing loops,  Prev: Boxed bitwise-integer masks,  Up: Libraries

6.2 Enumerated/finite types and sets
====================================

(This section was derived from work copyrighted (C) 1993-2005 by Richard
Kelsey, Jonathan Rees, and Mike Sperber.)

The structure 'finite-types' has two macros for defining "finite" or
"enumerated record types".  These are record types for which there is a
fixed set of instances, all of which are created at the same time as the
record type itself.  Also, the structure 'enum-sets' has several
utilities for building sets of the instances of those types, although it
is generalized beyond the built-in enumerated/finite type device.  There
is considerable overlap between the boxed bitwise-integer mask library
(*note Boxed bitwise-integer masks::) and the enumerated set facility.

6.2.1 Enumerated/finite types
-----------------------------

 -- syntax: define-enumerated-type
          (define-enumerated-type DISPATCHER TYPE
            PREDICATE
            INSTANCE-VECTOR
            NAME-ACCESSOR
            INDEX-ACCESSOR
            (INSTANCE-NAME
             ...))
     This defines a new record type, to which TYPE is bound, with as
     many instances as there are INSTANCE-NAMEs.  PREDICATE is defined
     to be the record type's predicate.  INSTANCE-VECTOR is defined to
     be a vector containing the instances of the type in the same order
     as the INSTANCE-NAME list.  DISPATCHER is defined to be a macro of
     the form (DISPATCHER INSTANCE-NAME); it evaluates to the instance
     with the given name, which is resolved at macro-expansion time.
     NAME-ACCESSOR & INDEX-ACCESSOR are defined to be unary procedures
     that return the symbolic name & index into the instance vector,
     respectively, of the new record type's instances.

     For example,

          (define-enumerated-type colour :colour
            colour?
            colours
            colour-name
            colour-index
            (black white purple maroon))

          (colour-name (vector-ref colours 0))    => black
          (colour-name (colour white))            => white
          (colour-index (colour purple))          => 2

 -- syntax: define-finite-type
          (define-finite-type DISPATCHER TYPE
            (FIELD-TAG ...)
            PREDICATE
            INSTANCE-VECTOR
            NAME-ACCESSOR
            INDEX-ACCESSOR
            (FIELD-TAG ACCESSOR [MODIFIER])
            ...
            ((INSTANCE-NAME FIELD-VALUE ...)
             ...))
     This is like 'define-enumerated-type', but the instances can also
     have added fields beyond the name and the accessor.  The first list
     of field tags lists the fields that each instance is constructed
     with, and each instance is constructed by applying the unnamed
     constructor to the initial field values listed.  Fields not listed
     in the first field tag list must be assigned later.

     For example,

          (define-finite-type colour :colour
            (red green blue)
            colour?
            colours
            colour-name
            colour-index
            (red   colour-red)
            (green colour-green)
            (blue  colour-blue)
            ((black    0   0   0)
             (white  255 255 255)
             (purple 160  32 240)
             (maroon 176  48  96)))

          (colour-name (colour black))            => black
          (colour-name (vector-ref colours 1))    => white
          (colour-index (colour purple))          => 2
          (colour-red (colour maroon))            => 176

6.2.2 Sets over enumerated types
--------------------------------

 -- syntax: define-enum-set-type
          (define-enum-set-type SET-SYNTAX TYPE
                                PREDICATE
                                LIST->X-SET
            ELEMENT-SYNTAX
            ELEMENT-PREDICATE
            ELEMENT-VECTOR
            ELEMENT-INDEX)
     This defines SET-SYNTAX to be a syntax for constructing sets, TYPE
     to be an object that represents the type of enumerated sets,
     PREDICATE to be a predicate for those sets, and LIST->X-SET to be a
     procedure that converts a list of elements into a set of the new
     type.

     ELEMENT-SYNTAX must be the name of a macro for constructing set
     elements from names (akin to the DISPATCHER argument to the
     'define-enumerated-type' & 'define-finite-type' forms).
     ELEMENT-PREDICATE must be a predicate for the element type,
     ELEMENT-VECTOR a vector of all values of the element type, and
     ELEMENT-INDEX a procedure that returns the index of an element
     within ELEMENT-VECTOR.

 -- procedure: enum-set->list enum-set --> element list
 -- procedure: enum-set-member? enum-set element --> boolean
 -- procedure: enum-set=? enum-set--_{a} enum-set--_{b} --> boolean
 -- procedure: enum-set-union enum-set--_{a} enum-set--_{b} --> enum-set
 -- procedure: enum-set-intersection enum-set--_{a} enum-set--_{b} -->
          enum-set
 -- procedure: enum-set-negation enum-set --> enum-set
     'Enum-set->list' returns a list of elements within ENUM-SET.
     'Enum-set-member?' tests whether ELEMENT is a member of ENUM-SET.
     'Enum-set=?' tests whether two enumerated sets are equal, i.e.
     contain all the same elements.  The other procedures perform
     standard set algebra operations on enumerated sets.  It is an error
     to pass an element that does not satisfy ENUM-SET's predicate to
     'enum-set-member?' or to pass two enumerated sets of different
     types to 'enum-set=?' or the enumerated set algebra operators.

   Here is a simple example of enumerated sets built atop the enumerated
types described in the previous section:

     (define-enumerated-type colour :colour
       colour?
       colours
       colour-name
       colour-index
       (red blue green))

     (define-enum-set-type colour-set :colour-set
                           colour-set?
                           list->colour-set
       colour colour? colours colour-index)

     (enum-set->list (colour-set red blue))
         => (#{Colour red} #{Colour blue})
     (enum-set->list (enum-set-negation (colour-set red blue)))
         => (#{Colour green})
     (enum-set-member? (colour-set red blue) (colour blue))
         => #t


File: scheme48.info,  Node: Macros for writing loops,  Next: Library data structures,  Prev: Enumerated/finite types and sets,  Up: Libraries

6.3 Macros for writing loops
============================

(This section was derived from work copyrighted (C) 1993-2005 by Richard
Kelsey, Jonathan Rees, and Mike Sperber.)

'Iterate' & 'reduce' are extensions of named-'let' for writing loops
that walk down one or more sequences, such as the elements of a list or
vector, the characters read from a port, or an arithmetic series.
Additional sequences can be defined by the user.  'Iterate' & 'reduce'
are exported by the structure 'reduce'.

* Menu:


* Main looping macros::
* Sequence types::
* Synchronous sequences::
* Examples::
* Defining sequence types::
* Loop macro expansion::


File: scheme48.info,  Node: Main looping macros,  Next: Sequence types,  Up: Macros for writing loops

6.3.1 Main looping macros
-------------------------

 -- syntax: iterate
          (iterate LOOP-NAME ((SEQ-TYPE ELT-VAR ARG ...)
                              ...)
              ((STATE-VAR INIT)
               ...)
            BODY
            [TAIL-EXP])
     'Iterate' steps the ELT-VARs in parallel through the sequences,
     while each STATE-VAR has the corresponding INIT for the first
     iteration and later values supplied by the body.  If any sequence
     has reached the limit, the value of the 'iterate' expression is the
     value of TAIL-EXP, if present, or the current values of the
     STATE-VARs, returned as multiple values.  If no sequence has
     reached its limit, BODY is evaluated and either calls LOOP-NAME
     with new values for the STATE-VARs or returns some other value(s).

     The LOOP-NAME and the STATE-VARs & INITs behave exactly as in
     named-'let', in that LOOP-NAME is bound only in the scope of BODY,
     and each INIT is evaluated parallel in the enclosing scope of the
     whole expression.  Also, the arguments to the sequence constructors
     will be evaluated in the enclosing scope of the whole expression,
     or in an extension of that scope peculiar to the sequence type.
     The named-'let' expression

          (let LOOP-NAME ((STATE-VAR INIT) ...)
            BODY
            ...)

     is equivalent to an iterate expression with no sequences (and with
     an explicit 'let' wrapped around the body expressions to take care
     of any internal definitions):

          (iterate LOOP-NAME ()
              ((STATE-VAR INIT) ...)
            (let () BODY ...))

     The SEQ-TYPEs are keywords (actually, macros of a particular form,
     which makes it easy to add additional types of sequences; see
     below).  Examples are 'list*', which walks down the elements of a
     list, and 'vector*', which does the same for vectors.  For each
     iteration, each ELT-VAR is bound to the next element of the
     sequence.  The ARGs are supplied to the sequence processors as
     other inputs, such as the list or vector to walk down.

     If there is a TAIL-EXP, it is evaluated when the end of one or more
     sequences is reached.  If the body does not call LOOP-NAME,
     however, the TAIL-EXP is not evaluated.  Unlike named-'let', the
     behaviour of a non-tail-recursive call to LOOP-NAME is unspecified,
     because iterating down a sequence may involve side effects, such as
     reading characters from a port.

 -- syntax: reduce
          (reduce ((SEQ-TYPE ELT-VAR ARG ...)
                   ...)
              ((STATE-VAR INIT)
               ...)
            BODY
            [TAIL-EXP])
     If an 'iterate' expression is not meant to terminate before a
     sequence has reached its end, the body will always end with a tail
     call to LOOP-NAME.  'Reduce' is a convenient macro that makes this
     common case explicit.  The syntax of 'reduce' is the same as that
     of 'iterate', except that there is no LOOP-NAME, and the body
     updates the state variables by returning multiple values in the
     stead of passing the new values to LOOP-NAME: the body must return
     as many values as there are state variables.  By special
     dispension, if there are no state variables, then the body may
     return any number of values, all of which are ignored.

     The value(s) returned by an instance of 'reduce' is (are) the
     value(s) returned by the TAIL-EXP, if present, or the current
     value(s) of the state variables when the end of one or more
     sequences is reached.

     A 'reduce' expression can be rewritten as an equivalent 'iterate'
     expression by adding a LOOP-NAME and a wrapper for the body that
     calls the LOOP-NAME:

          (iterate loop ((SEQ-TYPE ELT-VAR ARG ...)
                         ...)
              ((STATE-VAR INIT)
               ...)
            (call-with-values (lambda () BODY)
              loop)
            [TAIL-EXP])


File: scheme48.info,  Node: Sequence types,  Next: Synchronous sequences,  Prev: Main looping macros,  Up: Macros for writing loops

6.3.2 Sequence types
--------------------

 -- sequence type: list* elt-var list
 -- sequence type: vector* elt-var vector
 -- sequence type: string* elt-var string
 -- sequence type: count* elt-var start [end [step]]
 -- sequence type: input* elt-var input-port reader-proc
 -- sequence type: stream* elt-var proc initial-seed
     For lists, vectors, & strings, the ELT-VAR is bound to the
     successive elements of the list or vector, or the successive
     characters of the string.

     For 'count*', the ELT-VAR is bound to the elements of the sequence
     'start, start + step, start + 2*step, ..., end', inclusive of START
     and exclusive of END.  The default STEP is '1', and the sequence
     does not terminate if no END is given or if there is no N > 0 such
     that END = START + NSTEP.  ('=' is used to test for termination.)
     For example, '(count* i 0 -1)' does not terminate because it begins
     past the END value, and '(count* i 0 1 2)' does not terminate
     because it skips over the END value.

     For 'input*', the elements are the results of successive
     applications of READER-PROC to INPUT-PORT.  The sequence ends when
     the READER-PROC returns an end-of-file object, i.e. a value that
     satisfies 'eof-object?'.

     For 'stream*', the PROC receives the current seed as an argument
     and must return two values, the next value of the sequence & the
     next seed.  If the new seed is '#f', then the previous element was
     the last one.  For example, '(list* elt list)' is the same as

          (stream* elt
                   (lambda (list)
                     (if (null? list)
                         (values 'ignored #f)
                         (values (car list) (cdr list))))
                   list)


File: scheme48.info,  Node: Synchronous sequences,  Next: Examples,  Prev: Sequence types,  Up: Macros for writing loops

6.3.3 Synchronous sequences
---------------------------

When using the sequence types described above, a loop terminates when
any of its sequences terminate.  To help detect bugs, it is useful to
also have sequence types that check whether two or more sequences end on
the same iteration.  For this purpose, there is a second set of sequence
types called "synchronous sequences".  Synchronous sequences are like
ordinary asynchronous sequences in every respect except that they cause
an error to be signalled if a loop is terminated by a synchronous
sequence and some other synchronous sequence did not reach its end on
the same iteration.

   Sequences are checked for termination in order from left to right,
and if a loop is terminated by an asynchronous sequence no further
checking is done.

 -- synchronous sequence type: list% elt-var list
 -- synchronous sequence type: vector% elt-var vector
 -- synchronous sequence type: string% elt-var string
 -- synchronous sequence type: count% elt-var start end [step]
 -- synchronous sequence type: input% elt-var input-port reader-proc
 -- synchronous sequence type: stream% elt-var proc initial-seed
     These are all identical to their asynchronous equivalents above,
     except that they are synchronous.  Note that 'count%''s END
     argument is required, unlike 'count*''s, because it would be
     nonsensical to check for termination of a sequence that does not
     terminate.


File: scheme48.info,  Node: Examples,  Next: Defining sequence types,  Prev: Synchronous sequences,  Up: Macros for writing loops

6.3.4 Examples
--------------

Gathering the indices of list elements that answer true to some
predicate.

     (define (select-matching-items list pred)
       (reduce ((list* elt list)
                (count* i 0))
           ((hits '()))
         (if (pred elt)
             (cons i hits)
             hits)
         (reverse hits)))

   Finding the index of an element of a list that satisfies a predicate.

     (define (find-matching-item list pred)
       (iterate loop ((list* elt list)
                      (count* i 0))
           ()                                ; no state variables
         (if (pred elt)
             i
             (loop))))

   Reading one line of text from an input port.

     (define (read-line port)
       (iterate loop ((input* c port read-char))
           ((chars '()))
         (if (char=? c #\newline)
             (list->string (reverse chars))
             (loop (cons c chars)))
         (if (null? chars)
             (eof-object)                    ; from the PRIMITIVES structure
             (list->string (reverse chars)))))

   Counting the lines in a file.  This must be written in a way other
than with 'count*' because it needs the value of the count after the
loop has finished, but the count variable would not be bound then.

     (define (line-count filename)
       (call-with-input-file filename
         (lambda (inport)
           (reduce ((input* line inport read-line))
               ((count 0))
             (+ count 1)))))


File: scheme48.info,  Node: Defining sequence types,  Next: Loop macro expansion,  Prev: Examples,  Up: Macros for writing loops

6.3.5 Defining sequence types
-----------------------------

The sequence types are object-oriented macros similar to enumerations.
An asynchronous sequence macro needs to supply three values: '#f' to
indicate that it is not synchronous, a list of state variables and their
initializers, and the code for one iteration.  The first two methods are
written in continuation-passing style: they take another macro and
argument to which to pass their result.  See [Friedman 00] for more
details on the theory behind how CPS macros work.  The 'sync' method
receives no extra arguments.  The 'state-vars' method is passed a list
of names that will be bound to the arguments of the sequence.  The final
method, for stepping the sequence forward, is passed the list of names
bound to the arguments and the list of state variables.  In addition,
there is a variable to be bound to the next element of the sequence, the
body expression for the loop, and an expression for terminating the
loop.

   As an example, the definition of 'list*' is:

     (define-syntax list*
       (syntax-rules (SYNC STATE-VARS STEP)
         ((LIST* SYNC (next more))
          (next #F more))
         ((LIST* STATE-VARS (start-list) (next more))
          (next ((list-var start-list)) more))
         ((LIST* STEP (start-list) (list-var) value-var loop-body tail-exp)
          (IF (NULL? list-var)
              tail-exp
              (LET ((value-var (CAR list-var))
                    (list-var  (CDR list-var)))
                loop-body)))))

   Synchronized sequences are similar, except that they need to provide
a termination test to be used when some other synchronized method
terminates the loop.  To continue the example:

     (define-syntax list%
       (syntax-rules (SYNC DONE)
         ((LIST% SYNC (next more))
          (next #T more))
         ((LIST% DONE (start-list) (list-var))
          (NULL? list-var))
         ((LIST% . anything-else)
          (LIST* . anything-else))))


File: scheme48.info,  Node: Loop macro expansion,  Prev: Defining sequence types,  Up: Macros for writing loops

6.3.6 Loop macro expansion
--------------------------

Here is an example of the expansion of the 'reduce' macro:

     (reduce ((list* x '(1 2 3)))
         ((r '()))
       (cons x r))
         ==>
     (let ((final (lambda (r) (values r)))
           (list '(1 2 3))
           (r '()))
       (let loop ((list list) (r r))
         (if (null? list)
             (final r)
             (let ((x    (car list))
                   (list (cdr list)))
               (let ((continue (lambda (r)
                                 (loop list r))))
                 (continue (cons x r)))))))

   The only mild inefficiencies in this code are the 'final' &
'continue' procedures, both of which could trivially be substituted
in-line.  The macro expander could easily perform the substitution for
'continue' when there is no explicit proceed variable, as in this case,
but not in general.


File: scheme48.info,  Node: Library data structures,  Next: I/O extensions,  Prev: Macros for writing loops,  Up: Libraries

6.4 Library data structures
===========================

Scheme48 includes several libraries for a variety of data structures.

6.4.1 Multi-dimensional arrays
------------------------------

The 'arrays' structure exports a facility for multi-dimensional arrays,
based on Alan Bawden's interface.

 -- procedure: make-array value dimension ... --> array
 -- procedure: array dimensions element ... --> array
 -- procedure: copy-array array ... --> array
     Array constructors.  'Make-array' constructs an array with the
     given dimensions, each of which must be an exact, non-negative
     integer, and fills all of the elements with VALUE.  'Array' creates
     an array with the given list of dimensions, which must be a list of
     exact, non-negative integers, and fills it with the given elements
     in row-major order.  The number of elements must be equal to the
     product of DIMENSIONS.  'Copy-array' constructs an array with the
     same dimensions and contents as ARRAY.

 -- procedure: array? object --> boolean
     Disjoint type predicate for arrays.

 -- procedure: array-shape array --> integer-list
     Returns the list of dimensions of ARRAY.

 -- procedure: array-ref array index ... --> value
 -- procedure: array-set! array value index ... --> unspecified
     Array element dereferencing and assignment.  Each INDEX must be in
     the half-open interval [0,D), where D is the respective dimension
     of ARRAY corresponding with that index.

 -- procedure: array->vector array --> vector
     Creates a vector of the elements in ARRAY in row-major order.

 -- procedure: make-shared-array array linear-map dimension ... -->
          array
     Creates a new array that shares storage with ARRAY and uses the
     procedure LINEAR-MAP to map indices in the new array to indices in
     ARRAY.  LINEAR-MAP must accept as many arguments as DIMENSION ...,
     each of which must be an exact, non-negative integer; and must
     return a list of exact, non-negative integers equal in length to
     the number of dimensions of ARRAY, and which must be valid indices
     into ARRAY.

6.4.2 Red/black search trees
----------------------------

Along with hash tables for general object maps, Scheme48 also provides
red/black binary search trees generalized across key equality comparison
& ordering functions, as opposed to key equality comparison & hash
functions with hash tables.  These names are exported by the
'search-trees' structure.

 -- procedure: make-search-tree key= key< --> search-tree
 -- procedure: search-tree? object --> boolean
     'Make-search-tree' creates a new search tree with the given key
     equality comparison & ordering functions.  'Search-tree?' is the
     disjoint type predicate for red/black binary search trees.

 -- procedure: search-tree-ref search-tree key --> value or '#f'
 -- procedure: search-tree-set! search-tree key value --> unspecified
 -- procedure: search-tree-modify! search-tree key modifier -->
          unspecified
     'Search-tree-ref' returns the value associated with KEY in
     SEARCH-TREE, or '#f' if no such association exists.
     'Search-tree-set!' assigns the value of an existing association in
     SEARCH-TREE for KEY to be VALUE, if the association already exists;
     or, if not, it creates a new association with the given key and
     value.  If VALUE is '#f', however, any association is removed.
     'Search-tree-modify!' modifies the association in SEARCH-TREE for
     KEY by applying MODIFIER to the previous value of the association.
     If no association previously existed, one is created whose key is
     KEY and whose value is the result of applying MODIFIER to '#f'.  If
     MODIFIER returns '#f', the association is removed.  This is
     equivalent to '(search-tree-set! SEARCH-TREE KEY (MODIFIER
     (search-tree-ref SEARCH-TREE KEY)))', but it is implemented more
     efficiently.

 -- procedure: search-tree-max search-tree --> value or '#f'
 -- procedure: search-tree-min search-tree --> value or '#f'
 -- procedure: pop-search-tree-max! search-tree --> value or '#f'
 -- procedure: pop-search-tree-min! search-tree --> value or '#f'
     These all return two values: the key & value for the association in
     SEARCH-TREE whose key is the maximum or minimum of the tree.
     'Search-tree-max' and 'search-tree-min' do not remove the
     association from SEARCH-TREE; 'pop-search-tree-max!' and
     'pop-search-tree-min!' do.  If SEARCH-TREE is empty, these all
     return the two values '#f' and '#f'.

 -- procedure: walk-search-tree proc search-tree --> unspecified
     This applies PROC to two arguments, the key & value, for every
     association in SEARCH-TREE.

6.4.3 Sparse vectors
--------------------

Sparse vectors, exported by the structure 'sparse-vectors', are vectors
that grow as large as necessary without leaving large, empty spaces in
the vector.  They are implemented as trees of subvectors.

 -- procedure: make-sparse-vector --> sparse-vector
     Sparse vector constructor.

 -- procedure: sparse-vector-ref sparse-vector index --> value or '#f'
 -- procedure: sparse-vector-set! sparse-vector index value -->
          unspecified
     Sparse vector element accessor and modifier.  In the case of
     'sparse-vector-ref', if INDEX is beyond the highest index that was
     inserted into SPARSE-VECTOR, it returns '#f'; if
     'sparse-vector-set!' is passed an index beyond what was already
     assigned, it simply extends the vector.

 -- procedure: sparse-vector->list sparse-vector --> list
     Creates a list of the elements in SPARSE-VECTOR.  Elements that
     uninitialized gaps comprise are denoted by '#f' in the list.


File: scheme48.info,  Node: I/O extensions,  Next: TCP & UDP sockets,  Prev: Library data structures,  Up: Libraries

6.5 I/O extensions
==================

These facilities are all exported from the 'extended-ports' structure.

   Tracking ports track the line & column number that they are on.

 -- procedure: make-tracking-input-port sub-port --> input-port
 -- procedure: make-tracking-output-port sub-port --> output-port
     Tracking port constructors.  These simply create wrapper ports
     around SUB-PORT that track the line & column numbers.

 -- procedure: current-row port --> integer or '#f'
 -- procedure: current-column port --> integer or '#f'
     Accessors for line (row) & column number information.  If PORT is a
     not a tracking port, these simply return '#f'.

 -- procedure: fresh-line port --> unspecified
     This writes a newline to port with 'newline', unless it can be
     determined that the previous character was a newline -- that is, if
     '(current-column PORT)' does not evaluate to zero.

   These are ports based on procedures that produce and consume single
characters at a time.

 -- procedure: char-source->input-port char-producer [readiness-tester
          closer] --> input-port
 -- procedure: char-sink->output-port char-consumer --> output-port
     'Char-source->input-port' creates an input port that calls
     CHAR-PRODUCER with zero arguments when a character is read from it.
     If READINESS-TESTER is present, it is used for the 'char-ready?'
     operation on the resulting port; likewise with CLOSER and
     'close-input-port'.  'Char-sink->output-port' creates an output
     port that calls CHAR-CONSUMER for every character written to it.

   Scheme48 also provides ports that collect and produce output to and
from strings.

 -- procedure: make-string-input-port string --> input-port
     Constructs an input port whose contents are read from STRING.

 -- procedure: make-string-output-port --> output-port
 -- procedure: string-output-port-output string-port --> string
 -- procedure: call-with-string-output-port receiver --> string
     'Make-string-output-port' makes an output port that collects its
     output in a string.  'String-output-port-output' returns the string
     that STRING-PORT collected.  'Call-with-string-output-port' creates
     a string output port, applies RECEIVER to it, and returns the
     string that the string output port collected.

   Finally, there is a facility for writing only a limited quantity of
output to a given port.

 -- procedure: limit-output port count receiver --> unspecified
     'Limit-output' applies RECEIVER to a port that will write at most
     COUNT characters to PORT.


File: scheme48.info,  Node: TCP & UDP sockets,  Next: Common-Lisp-style formatting,  Prev: I/O extensions,  Up: Libraries

6.6 TCP & UDP sockets
=====================

Scheme48 provides a simple facility for TCP & UDP sockets.  Both the
structures 'sockets' and 'udp-sockets' export several general
socket-related procedures:

 -- procedure: close-socket socket --> unspecified
 -- procedure: socket-port-number socket --> integer
 -- procedure: get-host-name --> string
     'Close-socket' closes SOCKET, which may be any type of socket.
     'Socket-port-number' returns the port number through which SOCKET
     is communicating.  'Get-host-name' returns the network name of the
     current machine.

     *Note:* Programmers should be wary of storing the result of a call
     to 'get-host-name' in a dumped heap image, because the actual
     machine's host name may vary from invocation to invocation of the
     Scheme48 VM on that image, since heap images may be resumed on
     multiple different machines.

6.6.1 TCP sockets
-----------------

The 'sockets' structure provides simple TCP socket facilities.

 -- procedure: open-socket [port-number] --> socket
 -- procedure: socket-accept socket --> [input-port output-port]
     The server interface.  'Open-socket' creates a socket that listens
     on PORT-NUMBER, which defaults to a random number above 1024.
     'Socket-accept' blocks until there is a client waiting to be
     accepted, at which point it returns two values: an input port & an
     output port to send & receive data to & from the client.

 -- procedure: socket-client host-name port-number --> [input-port
          output-port]
     Connects to the server at PORT-NUMBER denoted by the machine name
     HOST-NAME and returns an input port and an output port for sending
     & receiving data to & from the server.  'Socket-client' blocks the
     current thread until the server accepts the connection request.

6.6.2 UDP sockets
-----------------

The 'udp-sockets' structure defines a UDP socket facility.

 -- procedure: open-udp-socket [port-number] --> socket
     Opens a UDP socket on PORT-NUMBER, or a random port number if none
     was passed.  'Open-udp-socket' returns two values: an input UDP
     socket and an output UDP socket.

 -- procedure: udp-send socket address buffer count --> count-sent
 -- procedure: udp-receive socket buffer --> [count-received
          remote-address]
     'Udp-send' attempts to send COUNT elements from the string or byte
     vector BUFFER from the output UDP socket SOCKET to the UDP address
     ADDRESS, and returns the number of octets it successfully sent.
     'Udp-receive' receives a UDP message from SOCKET, reading it into
     BUFFER destructively.  It returns two values: the number of octets
     read into BUFFER and the address whence the octets came.

 -- procedure: lookup-udp-address name port --> udp-address
 -- procedure: udp-address? object --> boolean
 -- procedure: udp-address-address address --> c-byte-vector
 -- procedure: udp-address-port address --> port-number
 -- procedure: udp-address-hostname address --> string-address
     'Lookup-udp-address' returns a UDP address for the machine name
     NAME at the port number PORT.  'Udp-address?' is the disjoint type
     predicate for UDP addresses.  'Udp-address-address' returns a byte
     vector that contains the C representation of ADDRESS, suitable for
     passing to C with Scheme48's C FFI. 'Udp-address-port' returns the
     port number of ADDRESS.  'Udp-address-hostname' returns a string
     representation of the IP address of ADDRESS.
